All of lore.kernel.org
 help / color / mirror / Atom feed
* [char-misc-next 01/11] mei: fix mei_poll operation
@ 2015-03-26 22:27 Tomas Winkler
  2015-03-26 22:27 ` [char-misc-next 02/11] mei: use mei_cl_is_connected consistently Tomas Winkler
                   ` (9 more replies)
  0 siblings, 10 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:27 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

mei_poll returned with POLLIN w/o checking whether the operation
has really completed.
remove redundant check and locking in amthif specific handler

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c | 25 +++++++++++++++----------
 drivers/misc/mei/client.c |  2 +-
 drivers/misc/mei/main.c   | 24 +++++++++++-------------
 3 files changed, 27 insertions(+), 24 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 7b6ed0bbfc9c..3c1fd87ee10b 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -362,6 +362,18 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
 	return mei_amthif_run_next_cmd(dev);
 }
 
+/**
+ * mei_amthif_poll - the amthif poll function
+ *
+ * @dev: the device structure
+ * @file: pointer to file structure
+ * @wait: pointer to poll_table structure
+ *
+ * Return: poll mask
+ *
+ * Locking: called under "dev->device_lock" lock
+ */
+
 unsigned int mei_amthif_poll(struct mei_device *dev,
 		struct file *file, poll_table *wait)
 {
@@ -369,19 +381,12 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
 
 	poll_wait(file, &dev->iamthif_cl.wait, wait);
 
-	mutex_lock(&dev->device_lock);
-	if (!mei_cl_is_connected(&dev->iamthif_cl)) {
-
-		mask = POLLERR;
-
-	} else if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
-		   dev->iamthif_file_object == file) {
+	if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
+	    dev->iamthif_file_object == file) {
 
-		mask |= (POLLIN | POLLRDNORM);
-		dev_dbg(dev->dev, "run next amthif cb\n");
+		mask |= POLLIN | POLLRDNORM;
 		mei_amthif_run_next_cmd(dev);
 	}
-	mutex_unlock(&dev->device_lock);
 
 	return mask;
 }
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 4290185c65de..d6304fb30ccf 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1298,7 +1298,7 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 	} else if (cb->fop_type == MEI_FOP_READ) {
 		list_add_tail(&cb->list, &cl->rd_completed);
 		if (waitqueue_active(&cl->rx_wait))
-			wake_up_interruptible(&cl->rx_wait);
+			wake_up_interruptible_all(&cl->rx_wait);
 		else
 			mei_cl_bus_rx_event(cl);
 
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index d80867e0d803..a1ec45054988 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -542,6 +542,7 @@ static long mei_compat_ioctl(struct file *file,
  */
 static unsigned int mei_poll(struct file *file, poll_table *wait)
 {
+	unsigned long req_events = poll_requested_events(wait);
 	struct mei_cl *cl = file->private_data;
 	struct mei_device *dev;
 	unsigned int mask = 0;
@@ -558,22 +559,19 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
 		goto out;
 	}
 
-	mutex_unlock(&dev->device_lock);
-
-
-	if (cl == &dev->iamthif_cl)
-		return mei_amthif_poll(dev, file, wait);
-
-	poll_wait(file, &cl->tx_wait, wait);
-
-	mutex_lock(&dev->device_lock);
-
-	if (!mei_cl_is_connected(cl)) {
-		mask = POLLERR;
+	if (cl == &dev->iamthif_cl) {
+		mask = mei_amthif_poll(dev, file, wait);
 		goto out;
 	}
 
-	mask |= (POLLIN | POLLRDNORM);
+	if (req_events & (POLLIN | POLLRDNORM)) {
+		poll_wait(file, &cl->rx_wait, wait);
+
+		if (!list_empty(&cl->rd_completed))
+			mask |= POLLIN | POLLRDNORM;
+		else
+			mei_cl_read_start(cl, 0, file);
+	}
 
 out:
 	mutex_unlock(&dev->device_lock);
-- 
1.9.3


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

* [char-misc-next 02/11] mei: use mei_cl_is_connected consistently
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
@ 2015-03-26 22:27 ` Tomas Winkler
  2015-03-26 22:27 ` [char-misc-next 03/11] mei: replace check for connection instead of transitioning Tomas Winkler
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:27 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

Replace open coded check for cl->state !=/== MEI_FILE_CONNECTED
with mei_cl_is_connected function.

Note that cl->state != MEI_FILE_CONNECTED is not the same
as cl->state == MEI_FILE_DISCONNECTED

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c       |  4 ++--
 drivers/misc/mei/client.c    |  2 +-
 drivers/misc/mei/interrupt.c |  2 +-
 drivers/misc/mei/main.c      | 13 +++++++------
 drivers/misc/mei/wd.c        | 18 +++++++++++-------
 5 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 45896f95fed1..b724a67696fc 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -238,7 +238,7 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 	dev = cl->dev;
 
 	mutex_lock(&dev->device_lock);
-	if (cl->state != MEI_FILE_CONNECTED) {
+	if (!mei_cl_is_connected(cl)) {
 		rets = -ENODEV;
 		goto out;
 	}
@@ -474,7 +474,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
 
 	mutex_lock(&dev->device_lock);
 
-	if (cl->state != MEI_FILE_CONNECTED) {
+	if (!mei_cl_is_connected(cl)) {
 		dev_err(dev->dev, "Already disconnected");
 		err = 0;
 		goto out;
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index d6304fb30ccf..43f56e0481ce 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -876,7 +876,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
 			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
 	mutex_lock(&dev->device_lock);
 
-	if (cl->state != MEI_FILE_CONNECTED) {
+	if (!mei_cl_is_connected(cl)) {
 		cl->state = MEI_FILE_DISCONNECTED;
 		/* something went really wrong */
 		if (!cl->status)
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 3f23629759db..3f84d2edcde4 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -110,7 +110,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 		goto out;
 	}
 
-	if (cl->state != MEI_FILE_CONNECTED) {
+	if (!mei_cl_is_connected(cl)) {
 		cl_dbg(dev, cl, "not connected\n");
 		cb->status = -ENODEV;
 		goto out;
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index a1ec45054988..29fa88b6fa17 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -107,7 +107,7 @@ static int mei_release(struct inode *inode, struct file *file)
 		rets = mei_amthif_release(dev, file);
 		goto out;
 	}
-	if (cl->state == MEI_FILE_CONNECTED) {
+	if (mei_cl_is_connected(cl)) {
 		cl->state = MEI_FILE_DISCONNECTING;
 		cl_dbg(dev, cl, "disconnecting\n");
 		rets = mei_cl_disconnect(cl);
@@ -309,9 +309,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 		goto out;
 	}
 
-	if (cl->state != MEI_FILE_CONNECTED) {
-		dev_err(dev->dev, "host client = %d,  is not connected to ME client = %d",
-			cl->host_client_id, cl->me_client_id);
+	if (!mei_cl_is_connected(cl)) {
+		cl_err(dev, cl, "is not connected");
 		rets = -ENODEV;
 		goto out;
 	}
@@ -418,7 +417,7 @@ static int mei_ioctl_connect_client(struct file *file,
 	 */
 	if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
 		dev_dbg(dev->dev, "FW Client is amthi\n");
-		if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
+		if (!mei_cl_is_connected(&dev->iamthif_cl)) {
 			rets = -ENODEV;
 			goto end;
 		}
@@ -554,7 +553,9 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
 
 	mutex_lock(&dev->device_lock);
 
-	if (!mei_cl_is_connected(cl)) {
+
+	if (dev->dev_state != MEI_DEV_ENABLED ||
+	    !mei_cl_is_connected(cl)) {
 		mask = POLLERR;
 		goto out;
 	}
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index ac1e6235692d..2725f865c3d6 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -160,9 +160,10 @@ int mei_wd_send(struct mei_device *dev)
  */
 int mei_wd_stop(struct mei_device *dev)
 {
+	struct mei_cl *cl = &dev->wd_cl;
 	int ret;
 
-	if (dev->wd_cl.state != MEI_FILE_CONNECTED ||
+	if (!mei_cl_is_connected(cl) ||
 	    dev->wd_state != MEI_WD_RUNNING)
 		return 0;
 
@@ -170,7 +171,7 @@ int mei_wd_stop(struct mei_device *dev)
 
 	dev->wd_state = MEI_WD_STOPPING;
 
-	ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
+	ret = mei_cl_flow_ctrl_creds(cl);
 	if (ret < 0)
 		goto err;
 
@@ -211,13 +212,16 @@ err:
  */
 static int mei_wd_ops_start(struct watchdog_device *wd_dev)
 {
-	int err = -ENODEV;
 	struct mei_device *dev;
+	struct mei_cl *cl;
+	int err = -ENODEV;
 
 	dev = watchdog_get_drvdata(wd_dev);
 	if (!dev)
 		return -ENODEV;
 
+	cl = &dev->wd_cl;
+
 	mutex_lock(&dev->device_lock);
 
 	if (dev->dev_state != MEI_DEV_ENABLED) {
@@ -226,8 +230,8 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
 		goto end_unlock;
 	}
 
-	if (dev->wd_cl.state != MEI_FILE_CONNECTED)	{
-		dev_dbg(dev->dev, "MEI Driver is not connected to Watchdog Client\n");
+	if (!mei_cl_is_connected(cl)) {
+		cl_dbg(dev, cl, "MEI Driver is not connected to Watchdog Client\n");
 		goto end_unlock;
 	}
 
@@ -282,8 +286,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
 
 	mutex_lock(&dev->device_lock);
 
-	if (cl->state != MEI_FILE_CONNECTED) {
-		dev_err(dev->dev, "wd: not connected.\n");
+	if (!mei_cl_is_connected(cl)) {
+		cl_err(dev, cl, "wd: not connected.\n");
 		ret = -ENODEV;
 		goto end;
 	}
-- 
1.9.3


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

* [char-misc-next 03/11] mei: replace check for connection instead of transitioning
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
  2015-03-26 22:27 ` [char-misc-next 02/11] mei: use mei_cl_is_connected consistently Tomas Winkler
@ 2015-03-26 22:27 ` Tomas Winkler
  2015-03-26 22:28 ` [char-misc-next 04/11] mei: revamp client disconnection flow Tomas Winkler
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:27 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

The function mei_cl_is_transitioning is just opposite
of mei_cl_is_connected. What we actually wanted to
check is if we lost connection so we can discard
the check for transition and check for 'not connected'

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c    |  4 ++--
 drivers/misc/mei/client.h | 14 ++++++++------
 drivers/misc/mei/main.c   |  4 ++--
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index b724a67696fc..4cf38c39878a 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -302,7 +302,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
 
 		if (wait_event_interruptible(cl->rx_wait,
 				(!list_empty(&cl->rd_completed)) ||
-				mei_cl_is_transitioning(cl))) {
+				(!mei_cl_is_connected(cl)))) {
 
 			if (signal_pending(current))
 				return -EINTR;
@@ -311,7 +311,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
 
 		mutex_lock(&dev->device_lock);
 
-		if (mei_cl_is_transitioning(cl)) {
+		if (!mei_cl_is_connected(cl)) {
 			rets = -EBUSY;
 			goto out;
 		}
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 7800d1bd8ba1..0a39e5d45171 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -90,16 +90,18 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
 /*
  *  MEI input output function prototype
  */
+
+/**
+ * mei_cl_is_connected - host client is connected
+ *
+ * @cl: host clinet
+ *
+ * Return: true if the host clinet is connected
+ */
 static inline bool mei_cl_is_connected(struct mei_cl *cl)
 {
 	return  cl->state == MEI_FILE_CONNECTED;
 }
-static inline bool mei_cl_is_transitioning(struct mei_cl *cl)
-{
-	return  MEI_FILE_INITIALIZING == cl->state ||
-		MEI_FILE_DISCONNECTED == cl->state ||
-		MEI_FILE_DISCONNECTING == cl->state;
-}
 
 bool mei_cl_is_other_connecting(struct mei_cl *cl);
 int mei_cl_disconnect(struct mei_cl *cl);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 29fa88b6fa17..7f77f39c24a7 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -203,7 +203,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
 
 		if (wait_event_interruptible(cl->rx_wait,
 				(!list_empty(&cl->rd_completed)) ||
-				mei_cl_is_transitioning(cl))) {
+				(!mei_cl_is_connected(cl)))) {
 
 			if (signal_pending(current))
 				return -EINTR;
@@ -211,7 +211,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
 		}
 
 		mutex_lock(&dev->device_lock);
-		if (mei_cl_is_transitioning(cl)) {
+		if (!mei_cl_is_connected(cl)) {
 			rets = -EBUSY;
 			goto out;
 		}
-- 
1.9.3


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

* [char-misc-next 04/11] mei: revamp client disconnection flow
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
  2015-03-26 22:27 ` [char-misc-next 02/11] mei: use mei_cl_is_connected consistently Tomas Winkler
  2015-03-26 22:27 ` [char-misc-next 03/11] mei: replace check for connection instead of transitioning Tomas Winkler
@ 2015-03-26 22:28 ` Tomas Winkler
  2015-04-03 14:19   ` Greg KH
  2015-03-26 22:28 ` [char-misc-next 05/11] mei: revamp client connection Tomas Winkler
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:28 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler, Alexander Usyskin

Split disconnected state into two parts first reception disconnect
response from the firmware and second actually setting of disconnected
state.  Book keeping data are needed for processing and after firmware
disconnected the client and are cleaned when setting the disconnected
state in mei_cl_set_disconneted() function.
Add mei_cl_send_disconnect to reduce code duplication.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/bus.c       |   2 -
 drivers/misc/mei/client.c    | 158 +++++++++++++++++++++++++++++++++----------
 drivers/misc/mei/client.h    |   3 +
 drivers/misc/mei/hbm.c       |   8 +--
 drivers/misc/mei/interrupt.c |  46 +------------
 drivers/misc/mei/main.c      |   9 +--
 drivers/misc/mei/mei_dev.h   |   3 +-
 7 files changed, 134 insertions(+), 95 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 4cf38c39878a..873c1b6e45e8 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -480,8 +480,6 @@ int mei_cl_disable_device(struct mei_cl_device *device)
 		goto out;
 	}
 
-	cl->state = MEI_FILE_DISCONNECTING;
-
 	err = mei_cl_disconnect(cl);
 	if (err < 0) {
 		dev_err(dev->dev, "Could not disconnect from the ME client");
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 43f56e0481ce..e572ecd5a68d 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -546,6 +546,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
 	INIT_LIST_HEAD(&cl->link);
 	INIT_LIST_HEAD(&cl->device_link);
 	cl->writing_state = MEI_IDLE;
+	cl->state = MEI_FILE_INITIALIZING;
 	cl->dev = dev;
 }
 
@@ -715,6 +716,88 @@ bool mei_hbuf_acquire(struct mei_device *dev)
 }
 
 /**
+ * mei_cl_set_disconnected - set disconnected state and clear
+ *   associated states and resources
+ *
+ * @cl: host client
+ */
+void mei_cl_set_disconnected(struct mei_cl *cl)
+{
+	struct mei_device *dev = cl->dev;
+
+	if (cl->state == MEI_FILE_DISCONNECTED ||
+	    cl->state == MEI_FILE_INITIALIZING)
+		return;
+
+	cl->state = MEI_FILE_DISCONNECTED;
+	mei_io_list_flush(&dev->ctrl_rd_list, cl);
+	mei_io_list_flush(&dev->ctrl_wr_list, cl);
+	cl->mei_flow_ctrl_creds = 0;
+	cl->timer_count = 0;
+}
+
+/*
+ * mei_cl_send_disconnect - send disconnect request
+ *
+ * @cl: host client
+ * @cb: callback block
+ *
+ * Return: 0, OK; otherwise, error.
+ */
+static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb)
+{
+	struct mei_device *dev;
+	int ret;
+
+	dev = cl->dev;
+
+	ret = mei_hbm_cl_disconnect_req(dev, cl);
+	cl->status = ret;
+	if (ret) {
+		cl->state = MEI_FILE_DISCONNECT_REPLY;
+		return ret;
+	}
+
+	list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
+	cl->timer_count = MEI_CONNECT_TIMEOUT;
+
+	return 0;
+}
+
+/**
+ * mei_cl_irq_disconnect - processes close related operation from
+ *	interrupt thread context - send disconnect request
+ *
+ * @cl: client
+ * @cb: callback block.
+ * @cmpl_list: complete list.
+ *
+ * Return: 0, OK; otherwise, error.
+ */
+int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
+			    struct mei_cl_cb *cmpl_list)
+{
+	struct mei_device *dev = cl->dev;
+	u32 msg_slots;
+	int slots;
+	int ret;
+
+	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+	slots = mei_hbuf_empty_slots(dev);
+
+	if (slots < msg_slots)
+		return -EMSGSIZE;
+
+	ret = mei_cl_send_disconnect(cl, cb);
+	if (ret)
+		list_move_tail(&cb->list, &cmpl_list->list);
+
+	return ret;
+}
+
+
+
+/**
  * mei_cl_disconnect - disconnect host client from the me one
  *
  * @cl: host client
@@ -736,7 +819,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
 
 	cl_dbg(dev, cl, "disconnecting");
 
-	if (cl->state != MEI_FILE_DISCONNECTING)
+	if (!mei_cl_is_connected(cl))
 		return 0;
 
 	rets = pm_runtime_get(dev->dev);
@@ -746,44 +829,41 @@ int mei_cl_disconnect(struct mei_cl *cl)
 		return rets;
 	}
 
+	cl->state = MEI_FILE_DISCONNECTING;
+
 	cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
 	rets = cb ? 0 : -ENOMEM;
 	if (rets)
-		goto free;
+		goto out;
+
+	cl_dbg(dev, cl, "add disconnect cb to control write list\n");
+	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 
 	if (mei_hbuf_acquire(dev)) {
-		if (mei_hbm_cl_disconnect_req(dev, cl)) {
-			rets = -ENODEV;
+		rets = mei_cl_send_disconnect(cl, cb);
+		if (rets) {
 			cl_err(dev, cl, "failed to disconnect.\n");
-			goto free;
+			goto out;
 		}
-		cl->timer_count = MEI_CONNECT_TIMEOUT;
-		mdelay(10); /* Wait for hardware disconnection ready */
-		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
-	} else {
-		cl_dbg(dev, cl, "add disconnect cb to control write list\n");
-		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
-
 	}
-	mutex_unlock(&dev->device_lock);
-
-	wait_event_timeout(cl->wait,
-			MEI_FILE_DISCONNECTED == cl->state,
-			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
 
+	mutex_unlock(&dev->device_lock);
+	wait_event_timeout(cl->wait, cl->state == MEI_FILE_DISCONNECT_REPLY,
+			   mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
 	mutex_lock(&dev->device_lock);
 
-	if (MEI_FILE_DISCONNECTED == cl->state) {
-		rets = 0;
-		cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
-	} else {
+	rets = cl->status;
+	if (cl->state != MEI_FILE_DISCONNECT_REPLY) {
 		cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
 		rets = -ETIME;
 	}
 
-	mei_io_list_flush(&dev->ctrl_rd_list, cl);
-	mei_io_list_flush(&dev->ctrl_wr_list, cl);
-free:
+out:
+	/* we disconnect also on error */
+	mei_cl_set_disconnected(cl);
+	if (!rets)
+		cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
+
 	cl_dbg(dev, cl, "rpm: autosuspend\n");
 	pm_runtime_mark_last_busy(dev->dev);
 	pm_runtime_put_autosuspend(dev->dev);
@@ -872,18 +952,15 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
 	mutex_unlock(&dev->device_lock);
 	wait_event_timeout(cl->wait,
 			(cl->state == MEI_FILE_CONNECTED ||
-			 cl->state == MEI_FILE_DISCONNECTED),
+			 cl->state == MEI_FILE_DISCONNECT_REPLY),
 			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
 	mutex_lock(&dev->device_lock);
 
 	if (!mei_cl_is_connected(cl)) {
-		cl->state = MEI_FILE_DISCONNECTED;
 		/* 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);
+		mei_cl_set_disconnected(cl);
 	}
 
 	rets = cl->status;
@@ -1289,19 +1366,30 @@ err:
  */
 void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 {
-	if (cb->fop_type == MEI_FOP_WRITE) {
+	switch (cb->fop_type) {
+	case MEI_FOP_WRITE:
 		mei_io_cb_free(cb);
 		cl->writing_state = MEI_WRITE_COMPLETE;
 		if (waitqueue_active(&cl->tx_wait))
 			wake_up_interruptible(&cl->tx_wait);
+		break;
 
-	} else if (cb->fop_type == MEI_FOP_READ) {
+	case MEI_FOP_READ:
 		list_add_tail(&cb->list, &cl->rd_completed);
 		if (waitqueue_active(&cl->rx_wait))
 			wake_up_interruptible_all(&cl->rx_wait);
 		else
 			mei_cl_bus_rx_event(cl);
+		break;
+
+	case MEI_FOP_CONNECT:
+	case MEI_FOP_DISCONNECT:
+		if (waitqueue_active(&cl->wait))
+			wake_up(&cl->wait);
 
+		break;
+	default:
+		BUG_ON(0);
 	}
 }
 
@@ -1311,16 +1399,12 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
  *
  * @dev: mei device
  */
-
 void mei_cl_all_disconnect(struct mei_device *dev)
 {
 	struct mei_cl *cl;
 
-	list_for_each_entry(cl, &dev->file_list, link) {
-		cl->state = MEI_FILE_DISCONNECTED;
-		cl->mei_flow_ctrl_creds = 0;
-		cl->timer_count = 0;
-	}
+	list_for_each_entry(cl, &dev->file_list, link)
+		mei_cl_set_disconnected(cl);
 }
 
 
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 0a39e5d45171..57ce177d5b3a 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -105,6 +105,9 @@ static inline bool mei_cl_is_connected(struct mei_cl *cl)
 
 bool mei_cl_is_other_connecting(struct mei_cl *cl);
 int mei_cl_disconnect(struct mei_cl *cl);
+void mei_cl_set_disconnected(struct mei_cl *cl);
+int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
+			  struct mei_cl_cb *cmpl_list);
 int mei_cl_connect(struct mei_cl *cl, struct file *file);
 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,
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 58da92565c5e..410e0297527e 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -572,7 +572,7 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl,
 	cl_dbg(dev, cl, "hbm: disconnect response status=%d\n", rs->status);
 
 	if (rs->status == MEI_CL_DISCONN_SUCCESS)
-		cl->state = MEI_FILE_DISCONNECTED;
+		cl->state = MEI_FILE_DISCONNECT_REPLY;
 	cl->status = 0;
 }
 
@@ -611,7 +611,7 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,
 	if (rs->status == MEI_CL_CONN_SUCCESS)
 		cl->state = MEI_FILE_CONNECTED;
 	else
-		cl->state = MEI_FILE_DISCONNECTED;
+		cl->state = MEI_FILE_DISCONNECT_REPLY;
 	cl->status = mei_cl_conn_status_to_errno(rs->status);
 }
 
@@ -680,8 +680,8 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
 
 	cl = mei_hbm_cl_find_by_cmd(dev, disconnect_req);
 	if (cl) {
-		cl_dbg(dev, cl, "disconnect request received\n");
-		cl->state = MEI_FILE_DISCONNECTED;
+		cl_dbg(dev, cl, "fw disconnect request received\n");
+		cl->state = MEI_FILE_DISCONNECTING;
 		cl->timer_count = 0;
 
 		cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT_RSP, NULL);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 3f84d2edcde4..6fd7ca9b3119 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -180,56 +180,12 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
 		return -EMSGSIZE;
 
 	ret = mei_hbm_cl_disconnect_rsp(dev, cl);
-
-	cl->state = MEI_FILE_DISCONNECTED;
-	cl->status = 0;
+	mei_cl_set_disconnected(cl);
 	mei_io_cb_free(cb);
 
 	return ret;
 }
 
-
-
-/**
- * mei_cl_irq_disconnect - processes close related operation from
- *	interrupt thread context - send disconnect request
- *
- * @cl: client
- * @cb: callback block.
- * @cmpl_list: complete list.
- *
- * Return: 0, OK; otherwise, error.
- */
-static int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
-			    struct mei_cl_cb *cmpl_list)
-{
-	struct mei_device *dev = cl->dev;
-	u32 msg_slots;
-	int slots;
-
-	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
-	slots = mei_hbuf_empty_slots(dev);
-
-	if (slots < msg_slots)
-		return -EMSGSIZE;
-
-	if (mei_hbm_cl_disconnect_req(dev, cl)) {
-		cl->status = 0;
-		cb->buf_idx = 0;
-		list_move_tail(&cb->list, &cmpl_list->list);
-		return -EIO;
-	}
-
-	cl->state = MEI_FILE_DISCONNECTING;
-	cl->status = 0;
-	cb->buf_idx = 0;
-	list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
-	cl->timer_count = MEI_CONNECT_TIMEOUT;
-
-	return 0;
-}
-
-
 /**
  * mei_cl_irq_read - processes client read related operation from the
  *	interrupt thread context - request for flow control credits
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 7f77f39c24a7..1ead9191dd13 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -95,7 +95,7 @@ static int mei_release(struct inode *inode, struct file *file)
 {
 	struct mei_cl *cl = file->private_data;
 	struct mei_device *dev;
-	int rets = 0;
+	int rets;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -ENODEV;
@@ -107,11 +107,8 @@ static int mei_release(struct inode *inode, struct file *file)
 		rets = mei_amthif_release(dev, file);
 		goto out;
 	}
-	if (mei_cl_is_connected(cl)) {
-		cl->state = MEI_FILE_DISCONNECTING;
-		cl_dbg(dev, cl, "disconnecting\n");
-		rets = mei_cl_disconnect(cl);
-	}
+	rets = mei_cl_disconnect(cl);
+
 	mei_cl_flush_queues(cl, file);
 	cl_dbg(dev, cl, "removing\n");
 
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index f066ecd71939..7b039f8ddb8f 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -88,7 +88,8 @@ enum file_state {
 	MEI_FILE_CONNECTING,
 	MEI_FILE_CONNECTED,
 	MEI_FILE_DISCONNECTING,
-	MEI_FILE_DISCONNECTED
+	MEI_FILE_DISCONNECT_REPLY,
+	MEI_FILE_DISCONNECTED,
 };
 
 /* MEI device states */
-- 
1.9.3


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

* [char-misc-next 05/11] mei: revamp client connection
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
                   ` (2 preceding siblings ...)
  2015-03-26 22:28 ` [char-misc-next 04/11] mei: revamp client disconnection flow Tomas Winkler
@ 2015-03-26 22:28 ` Tomas Winkler
  2015-03-26 22:28 ` [char-misc-next 06/11] mei: add a reference from the host client to the me client Tomas Winkler
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:28 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler, Alexander Usyskin

Simplify connect state machine by changing the logic around
Connection request in progress - only check if we have a callback in
relevant queue.
Extract common code into mei_cl_send_connect() function

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/bus.c       |  6 +++
 drivers/misc/mei/client.c    | 97 ++++++++++++++++++++++++++++++++++----------
 drivers/misc/mei/client.h    |  3 +-
 drivers/misc/mei/interrupt.c | 43 --------------------
 4 files changed, 83 insertions(+), 66 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 873c1b6e45e8..00b0cb2075fb 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -436,6 +436,12 @@ int mei_cl_enable_device(struct mei_cl_device *device)
 
 	mutex_lock(&dev->device_lock);
 
+	if (mei_cl_is_connected(cl)) {
+		mutex_unlock(&dev->device_lock);
+		dev_warn(dev->dev, "Already connected");
+		return -EBUSY;
+	}
+
 	err = mei_cl_connect(cl, NULL);
 	if (err < 0) {
 		mutex_unlock(&dev->device_lock);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index e572ecd5a68d..3f8bb90dbb58 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -881,28 +881,83 @@ out:
  *
  * Return: true if other client is connected, false - otherwise.
  */
-bool mei_cl_is_other_connecting(struct mei_cl *cl)
+static bool mei_cl_is_other_connecting(struct mei_cl *cl)
 {
 	struct mei_device *dev;
-	struct mei_cl *ocl; /* the other client */
-
-	if (WARN_ON(!cl || !cl->dev))
-		return false;
+	struct mei_cl_cb *cb;
 
 	dev = cl->dev;
 
-	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)
+	list_for_each_entry(cb, &dev->ctrl_rd_list.list, list) {
+		if (cb->fop_type == MEI_FOP_CONNECT &&
+		    cl->me_client_id == cb->cl->me_client_id)
 			return true;
-
 	}
 
 	return false;
 }
 
 /**
+ * mei_cl_send_connect - send connect request
+ *
+ * @cl: host client
+ * @cb: callback block
+ *
+ * Return: 0, OK; otherwise, error.
+ */
+static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb)
+{
+	struct mei_device *dev;
+	int ret;
+
+	dev = cl->dev;
+
+	ret = mei_hbm_cl_connect_req(dev, cl);
+	cl->status = ret;
+	if (ret) {
+		cl->state = MEI_FILE_DISCONNECT_REPLY;
+		return ret;
+	}
+
+	list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
+	cl->timer_count = MEI_CONNECT_TIMEOUT;
+	return 0;
+}
+
+/**
+ * mei_cl_irq_connect - send connect request in irq_thread context
+ *
+ * @cl: host client
+ * @cb: callback block
+ * @cmpl_list: complete list
+ *
+ * Return: 0, OK; otherwise, error.
+ */
+int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
+			      struct mei_cl_cb *cmpl_list)
+{
+	struct mei_device *dev = cl->dev;
+	u32 msg_slots;
+	int slots;
+	int rets;
+
+	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 -EMSGSIZE;
+
+	rets = mei_cl_send_connect(cl, cb);
+	if (rets)
+		list_move_tail(&cb->list, &cmpl_list->list);
+
+	return rets;
+}
+
+/**
  * mei_cl_connect - connect host client to the me one
  *
  * @cl: host client
@@ -935,18 +990,14 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
 	if (rets)
 		goto out;
 
+	cl->state = MEI_FILE_CONNECTING;
+	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+
 	/* run hbuf acquire last so we don't have to undo */
 	if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
-		cl->state = MEI_FILE_CONNECTING;
-		if (mei_hbm_cl_connect_req(dev, cl)) {
-			rets = -ENODEV;
+		rets = mei_cl_send_connect(cl, cb);
+		if (rets)
 			goto out;
-		}
-		cl->timer_count = MEI_CONNECT_TIMEOUT;
-		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
-	} else {
-		cl->state = MEI_FILE_INITIALIZING;
-		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 	}
 
 	mutex_unlock(&dev->device_lock);
@@ -957,20 +1008,22 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
 	mutex_lock(&dev->device_lock);
 
 	if (!mei_cl_is_connected(cl)) {
-		/* something went really wrong */
+		/* timeout or something went really wrong */
 		if (!cl->status)
 			cl->status = -EFAULT;
-		mei_cl_set_disconnected(cl);
 	}
 
 	rets = cl->status;
-
 out:
 	cl_dbg(dev, cl, "rpm: autosuspend\n");
 	pm_runtime_mark_last_busy(dev->dev);
 	pm_runtime_put_autosuspend(dev->dev);
 
 	mei_io_cb_free(cb);
+
+	if (!mei_cl_is_connected(cl))
+		mei_cl_set_disconnected(cl);
+
 	return rets;
 }
 
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 57ce177d5b3a..181aed992399 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -103,12 +103,13 @@ static inline bool mei_cl_is_connected(struct mei_cl *cl)
 	return  cl->state == MEI_FILE_CONNECTED;
 }
 
-bool mei_cl_is_other_connecting(struct mei_cl *cl);
 int mei_cl_disconnect(struct mei_cl *cl);
 void mei_cl_set_disconnected(struct mei_cl *cl);
 int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
 			  struct mei_cl_cb *cmpl_list);
 int mei_cl_connect(struct mei_cl *cl, struct file *file);
+int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
+			      struct mei_cl_cb *cmpl_list);
 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);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 6fd7ca9b3119..3b74e3b9b294 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -223,49 +223,6 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
 	return 0;
 }
 
-
-/**
- * mei_cl_irq_connect - send connect request in irq_thread context
- *
- * @cl: client
- * @cb: callback block.
- * @cmpl_list: complete list.
- *
- * Return: 0, OK; otherwise, error.
- */
-static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
-			      struct mei_cl_cb *cmpl_list)
-{
-	struct mei_device *dev = cl->dev;
-	u32 msg_slots;
-	int slots;
-	int ret;
-
-	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 -EMSGSIZE;
-
-	cl->state = MEI_FILE_CONNECTING;
-
-	ret = mei_hbm_cl_connect_req(dev, cl);
-	if (ret) {
-		cl->status = ret;
-		cb->buf_idx = 0;
-		list_del_init(&cb->list);
-		return ret;
-	}
-
-	list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
-	cl->timer_count = MEI_CONNECT_TIMEOUT;
-	return 0;
-}
-
-
 /**
  * mei_irq_read_handler - bottom half read routine after ISR to
  * handle the read processing.
-- 
1.9.3


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

* [char-misc-next 06/11] mei: add a reference from the host client to the me client
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
                   ` (3 preceding siblings ...)
  2015-03-26 22:28 ` [char-misc-next 05/11] mei: revamp client connection Tomas Winkler
@ 2015-03-26 22:28 ` Tomas Winkler
  2015-03-26 22:28 ` [char-misc-next 07/11] mei: fix flow control for single buffer clients Tomas Winkler
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:28 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

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

Keep a pointer to associated me client in the host client object to
eliminate me client searches. Check if the me client is active in the
firmware by checking if its is linked on the me clients list
Add accessors for the me client properties from host client.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c    |  19 ++-----
 drivers/misc/mei/bus.c       |  27 +++++++---
 drivers/misc/mei/client.c    | 118 +++++++++++++++++++------------------------
 drivers/misc/mei/client.h    |  84 +++++++++++++++++++++++++++---
 drivers/misc/mei/debugfs.c   |   2 +-
 drivers/misc/mei/hbm.c       |   4 +-
 drivers/misc/mei/interrupt.c |   4 +-
 drivers/misc/mei/main.c      |  31 +++++-------
 drivers/misc/mei/mei_dev.h   |  17 ++++---
 drivers/misc/mei/nfc.c       |  50 ++++++++----------
 drivers/misc/mei/wd.c        |  22 ++------
 11 files changed, 207 insertions(+), 171 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 3c1fd87ee10b..a0209f02a31a 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -60,28 +60,19 @@ void mei_amthif_reset_params(struct mei_device *dev)
  * mei_amthif_host_init - mei initialization amthif client.
  *
  * @dev: the device structure
+ * @me_cl: me client
  *
  * Return: 0 on success, <0 on failure.
  */
-int mei_amthif_host_init(struct mei_device *dev)
+int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 {
 	struct mei_cl *cl = &dev->iamthif_cl;
-	struct mei_me_client *me_cl;
 	int ret;
 
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
 
 	mei_cl_init(cl, dev);
 
-	me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
-	if (!me_cl) {
-		dev_info(dev->dev, "amthif: failed to find the client");
-		return -ENOTTY;
-	}
-
-	cl->me_client_id = me_cl->client_id;
-	cl->cl_uuid = me_cl->props.protocol_name;
-
 	/* Assign iamthif_mtu to the value received from ME  */
 
 	dev->iamthif_mtu = me_cl->props.max_msg_length;
@@ -91,15 +82,13 @@ int mei_amthif_host_init(struct mei_device *dev)
 	ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
 	if (ret < 0) {
 		dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
-		goto out;
+		return ret;
 	}
 
-	ret = mei_cl_connect(cl, NULL);
+	ret = mei_cl_connect(cl, me_cl, NULL);
 
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
 
-out:
-	mei_me_cl_put(me_cl);
 	return ret;
 }
 
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 00b0cb2075fb..0236ba8270d6 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -133,7 +133,13 @@ static struct bus_type mei_cl_bus_type = {
 
 static void mei_cl_dev_release(struct device *dev)
 {
-	kfree(to_mei_cl_device(dev));
+	struct mei_cl_device *device = to_mei_cl_device(dev);
+
+	if (!device)
+		return;
+
+	mei_me_cl_put(device->me_cl);
+	kfree(device);
 }
 
 static struct device_type mei_cl_device_type = {
@@ -146,13 +152,15 @@ struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev,
 	struct mei_cl *cl;
 
 	list_for_each_entry(cl, &dev->device_list, device_link) {
-		if (!uuid_le_cmp(uuid, cl->cl_uuid))
+		if (cl->me_cl && !uuid_le_cmp(uuid, *mei_cl_uuid(cl)))
 			return cl;
 	}
 
 	return NULL;
 }
+
 struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+					struct mei_me_client *me_cl,
 					uuid_le uuid, char *name,
 					struct mei_cl_ops *ops)
 {
@@ -168,6 +176,11 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
 	if (!device)
 		return NULL;
 
+	device->me_cl = mei_me_cl_get(me_cl);
+	if (!device->me_cl) {
+		kfree(device);
+		return NULL;
+	}
 	device->cl = cl;
 	device->ops = ops;
 
@@ -180,6 +193,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
 	status = device_register(&device->dev);
 	if (status) {
 		dev_err(dev->dev, "Failed to register MEI device\n");
+		mei_me_cl_put(device->me_cl);
 		kfree(device);
 		return NULL;
 	}
@@ -228,7 +242,6 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 			bool blocking)
 {
 	struct mei_device *dev;
-	struct mei_me_client *me_cl = NULL;
 	struct mei_cl_cb *cb = NULL;
 	ssize_t rets;
 
@@ -244,13 +257,12 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 	}
 
 	/* Check if we have an ME client device */
-	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
-	if (!me_cl) {
+	if (!mei_me_cl_is_active(cl->me_cl)) {
 		rets = -ENOTTY;
 		goto out;
 	}
 
-	if (length > me_cl->props.max_msg_length) {
+	if (length > mei_cl_mtu(cl)) {
 		rets = -EFBIG;
 		goto out;
 	}
@@ -266,7 +278,6 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 	rets = mei_cl_write(cl, cb, blocking);
 
 out:
-	mei_me_cl_put(me_cl);
 	mutex_unlock(&dev->device_lock);
 	if (rets < 0)
 		mei_io_cb_free(cb);
@@ -442,7 +453,7 @@ int mei_cl_enable_device(struct mei_cl_device *device)
 		return -EBUSY;
 	}
 
-	err = mei_cl_connect(cl, NULL);
+	err = mei_cl_connect(cl, device->me_cl, NULL);
 	if (err < 0) {
 		mutex_unlock(&dev->device_lock);
 		dev_err(dev->dev, "Could not connect to the ME client");
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 3f8bb90dbb58..aa1d35a51e9f 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -83,7 +83,7 @@ void mei_me_cl_put(struct mei_me_client *me_cl)
 }
 
 /**
- * __mei_me_cl_del  - delete me client form the list and decrease
+ * __mei_me_cl_del  - delete me client from the list and decrease
  *     reference counter
  *
  * @dev: mei device
@@ -96,11 +96,25 @@ 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);
+	list_del_init(&me_cl->list);
 	mei_me_cl_put(me_cl);
 }
 
 /**
+ * mei_me_cl_del - delete me client from the list and decrease
+ *     reference counter
+ *
+ * @dev: mei device
+ * @me_cl: me client
+ */
+void mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl)
+{
+	down_write(&dev->me_clients_rwsem);
+	__mei_me_cl_del(dev, me_cl);
+	up_write(&dev->me_clients_rwsem);
+}
+
+/**
  * mei_me_cl_add - add me client to the list
  *
  * @dev: mei device
@@ -317,7 +331,7 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
 {
 	return cl1 && cl2 &&
 		(cl1->host_client_id == cl2->host_client_id) &&
-		(cl1->me_client_id == cl2->me_client_id);
+		(mei_cl_me_id(cl1) == mei_cl_me_id(cl2));
 }
 
 /**
@@ -620,7 +634,7 @@ int mei_cl_link(struct mei_cl *cl, int id)
 }
 
 /**
- * mei_cl_unlink - remove me_cl from the list
+ * mei_cl_unlink - remove host client from the list
  *
  * @cl: host client
  *
@@ -668,17 +682,17 @@ void mei_host_client_init(struct work_struct *work)
 
 	me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
 	if (me_cl)
-		mei_amthif_host_init(dev);
+		mei_amthif_host_init(dev, me_cl);
 	mei_me_cl_put(me_cl);
 
 	me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
 	if (me_cl)
-		mei_wd_host_init(dev);
+		mei_wd_host_init(dev, me_cl);
 	mei_me_cl_put(me_cl);
 
 	me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
 	if (me_cl)
-		mei_nfc_host_init(dev);
+		mei_nfc_host_init(dev, me_cl);
 	mei_me_cl_put(me_cl);
 
 
@@ -734,6 +748,9 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
 	mei_io_list_flush(&dev->ctrl_wr_list, cl);
 	cl->mei_flow_ctrl_creds = 0;
 	cl->timer_count = 0;
+
+	mei_me_cl_put(cl->me_cl);
+	cl->me_cl = NULL;
 }
 
 /*
@@ -890,7 +907,7 @@ static bool mei_cl_is_other_connecting(struct mei_cl *cl)
 
 	list_for_each_entry(cb, &dev->ctrl_rd_list.list, list) {
 		if (cb->fop_type == MEI_FOP_CONNECT &&
-		    cl->me_client_id == cb->cl->me_client_id)
+		    mei_cl_me_id(cl) == mei_cl_me_id(cb->cl))
 			return true;
 	}
 
@@ -961,13 +978,15 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
  * mei_cl_connect - connect host client to the me one
  *
  * @cl: host client
+ * @me_cl: me client
  * @file: pointer to file structure
  *
  * Locking: called under "dev->device_lock" lock
  *
  * Return: 0 on success, <0 on failure.
  */
-int mei_cl_connect(struct mei_cl *cl, struct file *file)
+int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
+		   struct file *file)
 {
 	struct mei_device *dev;
 	struct mei_cl_cb *cb;
@@ -990,6 +1009,12 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
 	if (rets)
 		goto out;
 
+	cl->me_cl = mei_me_cl_get(me_cl);
+	if (!cl->me_cl) {
+		rets = -ENODEV;
+		goto out;
+	}
+
 	cl->state = MEI_FILE_CONNECTING;
 	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 
@@ -1064,36 +1089,20 @@ err:
  * @cl: private data of the file object
  *
  * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
- *	-ENOENT if mei_cl is not present
- *	-EINVAL if single_recv_buf == 0
  */
 int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 {
-	struct mei_device *dev;
-	struct mei_me_client *me_cl;
-	int rets = 0;
-
-	if (WARN_ON(!cl || !cl->dev))
+	if (WARN_ON(!cl || !cl->me_cl))
 		return -EINVAL;
 
-	dev = cl->dev;
-
 	if (cl->mei_flow_ctrl_creds > 0)
 		return 1;
 
-	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
-	if (!me_cl) {
-		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
-		return -ENOENT;
+	if (mei_cl_is_single_recv_buf(cl)) {
+		if (cl->me_cl->mei_flow_ctrl_creds > 0)
+			return 1;
 	}
-
-	if (me_cl->mei_flow_ctrl_creds > 0) {
-		rets = 1;
-		if (WARN_ON(me_cl->props.single_recv_buf == 0))
-			rets = -EINVAL;
-	}
-	mei_me_cl_put(me_cl);
-	return rets;
+	return 0;
 }
 
 /**
@@ -1103,43 +1112,23 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
  *
  * Return:
  *	0 on success
- *	-ENOENT when me client is not found
  *	-EINVAL when ctrl credits are <= 0
  */
 int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
 {
-	struct mei_device *dev;
-	struct mei_me_client *me_cl;
-	int rets;
-
-	if (WARN_ON(!cl || !cl->dev))
+	if (WARN_ON(!cl || !cl->me_cl))
 		return -EINVAL;
 
-	dev = cl->dev;
-
-	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
-	if (!me_cl) {
-		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
-		return -ENOENT;
-	}
-
-	if (me_cl->props.single_recv_buf) {
-		if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
-			rets = -EINVAL;
-			goto out;
-		}
-		me_cl->mei_flow_ctrl_creds--;
+	if (mei_cl_is_single_recv_buf(cl)) {
+		if (WARN_ON(cl->me_cl->mei_flow_ctrl_creds <= 0))
+			return -EINVAL;
+		cl->me_cl->mei_flow_ctrl_creds--;
 	} else {
-		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
-			rets = -EINVAL;
-			goto out;
-		}
+		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+			return -EINVAL;
 		cl->mei_flow_ctrl_creds--;
 	}
-	rets = 0;
-out:
-	mei_me_cl_put(me_cl);
-	return rets;
+	return 0;
 }
 
 /**
@@ -1155,7 +1144,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
 {
 	struct mei_device *dev;
 	struct mei_cl_cb *cb;
-	struct mei_me_client *me_cl;
 	int rets;
 
 	if (WARN_ON(!cl || !cl->dev))
@@ -1170,14 +1158,12 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
 	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);
+	if (!mei_me_cl_is_active(cl->me_cl)) {
+		cl_err(dev, cl, "no such me client\n");
 		return  -ENOTTY;
 	}
 	/* always allocate at least client max message */
-	length = max_t(size_t, length, me_cl->props.max_msg_length);
-	mei_me_cl_put(me_cl);
+	length = max_t(size_t, length, mei_cl_mtu(cl));
 
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
@@ -1254,7 +1240,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 	msg_slots = mei_data2slots(len);
 
 	mei_hdr.host_addr = cl->host_client_id;
-	mei_hdr.me_addr = cl->me_client_id;
+	mei_hdr.me_addr = mei_cl_me_id(cl);
 	mei_hdr.reserved = 0;
 	mei_hdr.internal = cb->internal;
 
@@ -1338,7 +1324,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 	cl->writing_state = MEI_IDLE;
 
 	mei_hdr.host_addr = cl->host_client_id;
-	mei_hdr.me_addr = cl->me_client_id;
+	mei_hdr.me_addr = mei_cl_me_id(cl);
 	mei_hdr.reserved = 0;
 	mei_hdr.msg_complete = 0;
 	mei_hdr.internal = cb->internal;
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 181aed992399..bba560e325b7 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -44,6 +44,18 @@ void mei_me_cl_rm_by_uuid_id(struct mei_device *dev,
 			     const uuid_le *uuid, u8 id);
 void mei_me_cl_rm_all(struct mei_device *dev);
 
+/**
+ * mei_me_cl_is_active - check whether me client is active in the fw
+ *
+ * @me_cl: me client
+ *
+ * Return: true if the me client is active in the firmware
+ */
+static inline bool mei_me_cl_is_active(const struct mei_me_client *me_cl)
+{
+	return !list_empty_careful(&me_cl->list);
+}
+
 /*
  * MEI IO Functions
  */
@@ -94,20 +106,82 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
 /**
  * mei_cl_is_connected - host client is connected
  *
- * @cl: host clinet
+ * @cl: host client
  *
- * Return: true if the host clinet is connected
+ * Return: true if the host client is connected
  */
 static inline bool mei_cl_is_connected(struct mei_cl *cl)
 {
 	return  cl->state == MEI_FILE_CONNECTED;
 }
 
+/**
+ * mei_cl_me_id - me client id
+ *
+ * @cl: host client
+ *
+ * Return: me client id or 0 if client is not connected
+ */
+static inline u8 mei_cl_me_id(const struct mei_cl *cl)
+{
+	return cl->me_cl ? cl->me_cl->client_id : 0;
+}
+
+/**
+ * mei_cl_mtu - maximal message that client can send and receive
+ *
+ * @cl: host client
+ *
+ * Return: mtu
+ */
+static inline size_t mei_cl_mtu(const struct mei_cl *cl)
+{
+	return cl->me_cl->props.max_msg_length;
+}
+
+/**
+ * mei_cl_is_fixed_address - check whether the me client uses fixed address
+ *
+ * @cl: host client
+ *
+ * Return: true if the client is connected and it has fixed me address
+ */
+static inline bool mei_cl_is_fixed_address(const struct mei_cl *cl)
+{
+	return cl->me_cl && cl->me_cl->props.fixed_address;
+}
+
+/**
+ * mei_cl_is_single_recv_buf- check whether the me client
+ *       uses single receiving buffer
+ *
+ * @cl: host client
+ *
+ * Return: true if single_recv_buf == 1; 0 otherwise
+ */
+static inline bool mei_cl_is_single_recv_buf(const struct mei_cl *cl)
+{
+	return cl->me_cl->props.single_recv_buf;
+}
+
+/**
+ * mei_cl_uuid -  client's uuid
+ *
+ * @cl: host client
+ *
+ * Return: return uuid of connected me client
+ */
+static inline const uuid_le *mei_cl_uuid(const struct mei_cl *cl)
+{
+	return &cl->me_cl->props.protocol_name;
+}
+
 int mei_cl_disconnect(struct mei_cl *cl);
 void mei_cl_set_disconnected(struct mei_cl *cl);
 int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
 			  struct mei_cl_cb *cmpl_list);
-int mei_cl_connect(struct mei_cl *cl, struct file *file);
+int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
+		   struct file *file);
 int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
 			      struct mei_cl_cb *cmpl_list);
 int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp);
@@ -121,14 +195,12 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
 
 void mei_host_client_init(struct work_struct *work);
 
-
-
 void mei_cl_all_disconnect(struct mei_device *dev);
 void mei_cl_all_wakeup(struct mei_device *dev);
 void mei_cl_all_write_clear(struct mei_device *dev);
 
 #define MEI_CL_FMT "cl:host=%02d me=%02d "
-#define MEI_CL_PRM(cl) (cl)->host_client_id, (cl)->me_client_id
+#define MEI_CL_PRM(cl) (cl)->host_client_id, mei_cl_me_id(cl)
 
 #define cl_dbg(dev, cl, format, arg...) \
 	dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index d9cd7e6ee484..3f6d855a7ecb 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -116,7 +116,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,
+			i, mei_cl_me_id(cl), cl->host_client_id, cl->state,
 			!list_empty(&cl->rd_completed), cl->writing_state);
 		i++;
 	}
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 410e0297527e..f620824f7c86 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -151,7 +151,7 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
 
 	cmd->hbm_cmd = hbm_cmd;
 	cmd->host_addr = cl->host_client_id;
-	cmd->me_addr = cl->me_client_id;
+	cmd->me_addr = mei_cl_me_id(cl);
 }
 
 /**
@@ -189,7 +189,7 @@ static inline
 bool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd)
 {
 	return cl->host_client_id == cmd->host_addr &&
-		cl->me_client_id == cmd->me_addr;
+		mei_cl_me_id(cl) == cmd->me_addr;
 }
 
 /**
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 3b74e3b9b294..74795676bb3b 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -66,7 +66,7 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl,
 			struct mei_msg_hdr *mei_hdr)
 {
 	return cl->host_client_id == mei_hdr->host_addr &&
-		cl->me_client_id == mei_hdr->me_addr;
+		mei_cl_me_id(cl) == mei_hdr->me_addr;
 }
 
 /**
@@ -182,6 +182,8 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
 	ret = mei_hbm_cl_disconnect_rsp(dev, cl);
 	mei_cl_set_disconnected(cl);
 	mei_io_cb_free(cb);
+	mei_me_cl_put(cl->me_cl);
+	cl->me_cl = NULL;
 
 	return ret;
 }
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 1ead9191dd13..dcaa7658e742 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -272,7 +272,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 			 size_t length, loff_t *offset)
 {
 	struct mei_cl *cl = file->private_data;
-	struct mei_me_client *me_cl = NULL;
 	struct mei_cl_cb *write_cb = NULL;
 	struct mei_device *dev;
 	unsigned long timeout = 0;
@@ -290,27 +289,27 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 		goto out;
 	}
 
-	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
-	if (!me_cl) {
-		rets = -ENOTTY;
+	if (!mei_cl_is_connected(cl)) {
+		cl_err(dev, cl, "is not connected");
+		rets = -ENODEV;
 		goto out;
 	}
 
-	if (length == 0) {
-		rets = 0;
+	if (!mei_me_cl_is_active(cl->me_cl)) {
+		rets = -ENOTTY;
 		goto out;
 	}
 
-	if (length > me_cl->props.max_msg_length) {
+	if (length > mei_cl_mtu(cl)) {
 		rets = -EFBIG;
 		goto out;
 	}
 
-	if (!mei_cl_is_connected(cl)) {
-		cl_err(dev, cl, "is not connected");
-		rets = -ENODEV;
+	if (length == 0) {
+		rets = 0;
 		goto out;
 	}
+
 	if (cl == &dev->iamthif_cl) {
 		write_cb = mei_amthif_find_read_list_entry(dev, file);
 
@@ -348,14 +347,12 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 				"amthif write failed with status = %d\n", rets);
 			goto out;
 		}
-		mei_me_cl_put(me_cl);
 		mutex_unlock(&dev->device_lock);
 		return length;
 	}
 
 	rets = mei_cl_write(cl, write_cb, false);
 out:
-	mei_me_cl_put(me_cl);
 	mutex_unlock(&dev->device_lock);
 	if (rets < 0)
 		mei_io_cb_free(write_cb);
@@ -395,15 +392,13 @@ static int mei_ioctl_connect_client(struct file *file,
 	me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
 	if (!me_cl || me_cl->props.fixed_address) {
 		dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
-				&data->in_client_uuid);
+			&data->in_client_uuid);
+		mei_me_cl_put(me_cl);
 		return  -ENOTTY;
 	}
 
-	cl->me_client_id = me_cl->client_id;
-	cl->cl_uuid = me_cl->props.protocol_name;
-
 	dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
-			cl->me_client_id);
+			me_cl->client_id);
 	dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n",
 			me_cl->props.protocol_version);
 	dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
@@ -439,7 +434,7 @@ static int mei_ioctl_connect_client(struct file *file,
 	client->protocol_version = me_cl->props.protocol_version;
 	dev_dbg(dev->dev, "Can connect?\n");
 
-	rets = mei_cl_connect(cl, file);
+	rets = mei_cl_connect(cl, me_cl, file);
 
 end:
 	mei_me_cl_put(me_cl);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 7b039f8ddb8f..711e4fa8b708 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -227,11 +227,11 @@ struct mei_cl_cb {
  * @rx_wait: wait queue for rx completion
  * @wait:  wait queue for management operation
  * @status: connection status
- * @cl_uuid: client uuid name
+ * @me_cl: fw client connected
  * @host_client_id: host id
- * @me_client_id: me/fw id
  * @mei_flow_ctrl_creds: transmit flow credentials
  * @timer_count:  watchdog timer for operation completion
+ * @reserved: reserved for alignment
  * @writing_state: state of the tx
  * @rd_pending: pending read credits
  * @rd_completed: completed read
@@ -247,11 +247,11 @@ struct mei_cl {
 	wait_queue_head_t rx_wait;
 	wait_queue_head_t wait;
 	int status;
-	uuid_le cl_uuid;
+	struct mei_me_client *me_cl;
 	u8 host_client_id;
-	u8 me_client_id;
 	u8 mei_flow_ctrl_creds;
 	u8 timer_count;
+	u8 reserved;
 	enum mei_file_transaction_states writing_state;
 	struct list_head rd_pending;
 	struct list_head rd_completed;
@@ -346,6 +346,7 @@ struct mei_cl_ops {
 };
 
 struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+					struct mei_me_client *me_cl,
 					uuid_le uuid, char *name,
 					struct mei_cl_ops *ops);
 void mei_cl_remove_device(struct mei_cl_device *device);
@@ -368,6 +369,7 @@ struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev, uuid_le uuid);
  * when being probed and shall use it for doing ME bus I/O.
  *
  * @dev: linux driver model device pointer
+ * @me_cl: me client
  * @cl: mei client
  * @ops: ME transport ops
  * @event_work: async work to execute event callback
@@ -380,6 +382,7 @@ struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev, uuid_le uuid);
 struct mei_cl_device {
 	struct device dev;
 
+	struct mei_me_client *me_cl;
 	struct mei_cl *cl;
 
 	const struct mei_cl_ops *ops;
@@ -653,7 +656,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
  */
 void mei_amthif_reset_params(struct mei_device *dev);
 
-int mei_amthif_host_init(struct mei_device *dev);
+int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
 
 int mei_amthif_read(struct mei_device *dev, struct file *file,
 		char __user *ubuf, size_t length, loff_t *offset);
@@ -680,7 +683,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots);
 /*
  * NFC functions
  */
-int mei_nfc_host_init(struct mei_device *dev);
+int mei_nfc_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
 void mei_nfc_host_exit(struct mei_device *dev);
 
 /*
@@ -690,7 +693,7 @@ extern const uuid_le mei_nfc_guid;
 
 int mei_wd_send(struct mei_device *dev);
 int mei_wd_stop(struct mei_device *dev);
-int mei_wd_host_init(struct mei_device *dev);
+int mei_wd_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
 /*
  * mei_watchdog_register  - Registering watchdog interface
  *   once we got connection to the WD Client
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index c3bcb63686d7..fb9ac42a28d2 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -91,6 +91,7 @@ struct mei_nfc_hci_hdr {
 /**
  * struct mei_nfc_dev - NFC mei device
  *
+ * @me_cl: NFC me client
  * @cl: NFC host client
  * @cl_info: NFC info host client
  * @init_work: perform connection to the info client
@@ -104,6 +105,7 @@ struct mei_nfc_hci_hdr {
  * @recv_req_id: reception message counter
  */
 struct mei_nfc_dev {
+	struct mei_me_client *me_cl;
 	struct mei_cl *cl;
 	struct mei_cl *cl_info;
 	struct work_struct init_work;
@@ -151,6 +153,7 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev)
 		kfree(ndev->cl_info);
 	}
 
+	mei_me_cl_put(ndev->me_cl);
 	kfree(ndev);
 }
 
@@ -417,6 +420,7 @@ static void mei_nfc_init(struct work_struct *work)
 	struct mei_cl_device *cldev;
 	struct mei_nfc_dev *ndev;
 	struct mei_cl *cl_info;
+	struct mei_me_client *me_cl_info;
 
 	ndev = container_of(work, struct mei_nfc_dev, init_work);
 
@@ -425,13 +429,22 @@ static void mei_nfc_init(struct work_struct *work)
 
 	mutex_lock(&dev->device_lock);
 
-	if (mei_cl_connect(cl_info, NULL) < 0) {
+	/* check for valid client id */
+	me_cl_info = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
+	if (!me_cl_info) {
+		mutex_unlock(&dev->device_lock);
+		dev_info(dev->dev, "nfc: failed to find the info client\n");
+		goto err;
+	}
+
+	if (mei_cl_connect(cl_info, me_cl_info, NULL) < 0) {
+		mei_me_cl_put(me_cl_info);
 		mutex_unlock(&dev->device_lock);
 		dev_err(dev->dev, "Could not connect to the NFC INFO ME client");
 
 		goto err;
 	}
-
+	mei_me_cl_put(me_cl_info);
 	mutex_unlock(&dev->device_lock);
 
 	if (mei_nfc_if_version(ndev) < 0) {
@@ -459,7 +472,8 @@ static void mei_nfc_init(struct work_struct *work)
 		return;
 	}
 
-	cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name, &nfc_ops);
+	cldev = mei_cl_add_device(dev, ndev->me_cl, mei_nfc_guid,
+				  ndev->bus_name, &nfc_ops);
 	if (!cldev) {
 		dev_err(dev->dev, "Could not add the NFC device to the MEI bus\n");
 
@@ -479,11 +493,10 @@ err:
 }
 
 
-int mei_nfc_host_init(struct mei_device *dev)
+int mei_nfc_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 {
 	struct mei_nfc_dev *ndev;
 	struct mei_cl *cl_info, *cl;
-	struct mei_me_client *me_cl = NULL;
 	int ret;
 
 
@@ -500,11 +513,9 @@ int mei_nfc_host_init(struct mei_device *dev)
 		goto err;
 	}
 
-	/* check for valid client id */
-	me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
-	if (!me_cl) {
-		dev_info(dev->dev, "nfc: failed to find the client\n");
-		ret = -ENOTTY;
+	ndev->me_cl = mei_me_cl_get(me_cl);
+	if (!ndev->me_cl) {
+		ret = -ENODEV;
 		goto err;
 	}
 
@@ -514,34 +525,16 @@ int mei_nfc_host_init(struct mei_device *dev)
 		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);
-	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) {
-		dev_info(dev->dev, "nfc: failed to find the client\n");
-		ret = -ENOTTY;
-		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);
-	me_cl = NULL;
-
 	list_add_tail(&cl->device_link, &dev->device_list);
 
 	ndev->cl = cl;
@@ -555,7 +548,6 @@ int mei_nfc_host_init(struct mei_device *dev)
 	return 0;
 
 err:
-	mei_me_cl_put(me_cl);
 	mei_nfc_free(ndev);
 
 	return ret;
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 2725f865c3d6..2bc0f5089f82 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -50,15 +50,15 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
  * mei_wd_host_init - connect to the watchdog client
  *
  * @dev: the device structure
+ * @me_cl: me client
  *
  * Return: -ENOTTY if wd client cannot be found
  *         -EIO if write has failed
  *         0 on success
  */
-int mei_wd_host_init(struct mei_device *dev)
+int mei_wd_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 {
 	struct mei_cl *cl = &dev->wd_cl;
-	struct mei_me_client *me_cl;
 	int ret;
 
 	mei_cl_init(cl, dev);
@@ -66,27 +66,13 @@ int mei_wd_host_init(struct mei_device *dev)
 	dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
 	dev->wd_state = MEI_WD_IDLE;
 
-
-	/* check for valid client id */
-	me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
-	if (!me_cl) {
-		dev_info(dev->dev, "wd: failed to find the client\n");
-		return -ENOTTY;
-	}
-
-	cl->me_client_id = me_cl->client_id;
-	cl->cl_uuid = me_cl->props.protocol_name;
-	mei_me_cl_put(me_cl);
-
 	ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
-
 	if (ret < 0) {
 		dev_info(dev->dev, "wd: failed link client\n");
 		return ret;
 	}
 
-	ret = mei_cl_connect(cl, NULL);
-
+	ret = mei_cl_connect(cl, me_cl, NULL);
 	if (ret) {
 		dev_err(dev->dev, "wd: failed to connect = %d\n", ret);
 		mei_cl_unlink(cl);
@@ -118,7 +104,7 @@ int mei_wd_send(struct mei_device *dev)
 	int ret;
 
 	hdr.host_addr = cl->host_client_id;
-	hdr.me_addr = cl->me_client_id;
+	hdr.me_addr = mei_cl_me_id(cl);
 	hdr.msg_complete = 1;
 	hdr.reserved = 0;
 	hdr.internal = 0;
-- 
1.9.3


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

* [char-misc-next 07/11] mei: fix flow control for single buffer clients
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
                   ` (4 preceding siblings ...)
  2015-03-26 22:28 ` [char-misc-next 06/11] mei: add a reference from the host client to the me client Tomas Winkler
@ 2015-03-26 22:28 ` Tomas Winkler
  2015-03-26 22:28 ` [char-misc-next 08/11] mei: support for fixed address clients Tomas Winkler
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:28 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

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

For ME clients that use single receiving buffer
the driver tracks credentials on mei_me_clients structure
for all connections. The driver needs to book keep the shared
resource correctly and track the connections, particularly
the credit has to be cleaned when there is no active connection
to a particular me client. This solves issue when subsequent
connection will not get an ill impression that it can write.

We add active connection counter the particular ME client and
when the counter reach zero, we clear the credits.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/client.c  | 29 +++++++++++++++++++++++------
 drivers/misc/mei/mei_dev.h |  4 ++++
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index aa1d35a51e9f..98335b435b75 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -749,10 +749,31 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
 	cl->mei_flow_ctrl_creds = 0;
 	cl->timer_count = 0;
 
+	if (!cl->me_cl)
+		return;
+
+	if (!WARN_ON(cl->me_cl->connect_count == 0))
+		cl->me_cl->connect_count--;
+
+	if (cl->me_cl->connect_count == 0)
+		cl->me_cl->mei_flow_ctrl_creds = 0;
+
 	mei_me_cl_put(cl->me_cl);
 	cl->me_cl = NULL;
 }
 
+static int mei_cl_set_connecting(struct mei_cl *cl, struct mei_me_client *me_cl)
+{
+	cl->me_cl = mei_me_cl_get(me_cl);
+	if (!cl->me_cl)
+		return -ENOENT;
+
+	cl->state = MEI_FILE_CONNECTING;
+	cl->me_cl->connect_count++;
+
+	return 0;
+}
+
 /*
  * mei_cl_send_disconnect - send disconnect request
  *
@@ -1009,13 +1030,9 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
 	if (rets)
 		goto out;
 
-	cl->me_cl = mei_me_cl_get(me_cl);
-	if (!cl->me_cl) {
-		rets = -ENODEV;
+	rets = mei_cl_set_connecting(cl, me_cl);
+	if (rets)
 		goto out;
-	}
-
-	cl->state = MEI_FILE_CONNECTING;
 	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 
 	/* run hbuf acquire last so we don't have to undo */
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 711e4fa8b708..f17979c680a9 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -177,6 +177,8 @@ struct mei_fw_status {
  * @props: client properties
  * @client_id: me client id
  * @mei_flow_ctrl_creds: flow control credits
+ * @connect_count: number connections to this client
+ * @reserved: reserved
  */
 struct mei_me_client {
 	struct list_head list;
@@ -184,6 +186,8 @@ struct mei_me_client {
 	struct mei_client_properties props;
 	u8 client_id;
 	u8 mei_flow_ctrl_creds;
+	u8 connect_count;
+	u8 reserved;
 };
 
 
-- 
1.9.3


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

* [char-misc-next 08/11] mei: support for fixed address clients
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
                   ` (5 preceding siblings ...)
  2015-03-26 22:28 ` [char-misc-next 07/11] mei: fix flow control for single buffer clients Tomas Winkler
@ 2015-03-26 22:28 ` Tomas Winkler
  2015-03-26 22:28 ` [char-misc-next 09/11] mei: connection to fixed address clients from user-space Tomas Winkler
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:28 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

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

Fixed address is simplified FW client that doesn't require
connection and doesn't support flow control.
So it can be only one host client per fixed FW client.
Fixed client access is available only for drivers on mei bus,
connection from user-space is blocked.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/client.c    | 69 ++++++++++++++++++++++++++++++++++----------
 drivers/misc/mei/client.h    | 12 ++++++++
 drivers/misc/mei/hbm.c       |  4 +--
 drivers/misc/mei/interrupt.c |  2 +-
 4 files changed, 68 insertions(+), 19 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 98335b435b75..36706705dfdc 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -764,10 +764,18 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
 
 static int mei_cl_set_connecting(struct mei_cl *cl, struct mei_me_client *me_cl)
 {
-	cl->me_cl = mei_me_cl_get(me_cl);
-	if (!cl->me_cl)
+	if (!mei_me_cl_get(me_cl))
 		return -ENOENT;
 
+	/* only one connection is allowed for fixed address clients */
+	if (me_cl->props.fixed_address) {
+		if (me_cl->connect_count) {
+			mei_me_cl_put(me_cl);
+			return -EBUSY;
+		}
+	}
+
+	cl->me_cl = me_cl;
 	cl->state = MEI_FILE_CONNECTING;
 	cl->me_cl->connect_count++;
 
@@ -860,6 +868,11 @@ int mei_cl_disconnect(struct mei_cl *cl)
 	if (!mei_cl_is_connected(cl))
 		return 0;
 
+	if (mei_cl_is_fixed_address(cl)) {
+		mei_cl_set_disconnected(cl);
+		return 0;
+	}
+
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
 		pm_runtime_put_noidle(dev->dev);
@@ -1013,16 +1026,25 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
 	struct mei_cl_cb *cb;
 	int rets;
 
-	if (WARN_ON(!cl || !cl->dev))
+	if (WARN_ON(!cl || !cl->dev || !me_cl))
 		return -ENODEV;
 
 	dev = cl->dev;
 
+	rets = mei_cl_set_connecting(cl, me_cl);
+	if (rets)
+		return rets;
+
+	if (mei_cl_is_fixed_address(cl)) {
+		cl->state = MEI_FILE_CONNECTED;
+		return 0;
+	}
+
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
 		pm_runtime_put_noidle(dev->dev);
 		cl_err(dev, cl, "rpm: get failed %d\n", rets);
-		return rets;
+		goto nortpm;
 	}
 
 	cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
@@ -1030,9 +1052,6 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
 	if (rets)
 		goto out;
 
-	rets = mei_cl_set_connecting(cl, me_cl);
-	if (rets)
-		goto out;
 	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 
 	/* run hbuf acquire last so we don't have to undo */
@@ -1063,6 +1082,7 @@ out:
 
 	mei_io_cb_free(cb);
 
+nortpm:
 	if (!mei_cl_is_connected(cl))
 		mei_cl_set_disconnected(cl);
 
@@ -1109,12 +1129,21 @@ err:
  */
 int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 {
+	int rets;
+
 	if (WARN_ON(!cl || !cl->me_cl))
 		return -EINVAL;
 
 	if (cl->mei_flow_ctrl_creds > 0)
 		return 1;
 
+	if (mei_cl_is_fixed_address(cl)) {
+		rets = mei_cl_read_start(cl, mei_cl_mtu(cl), NULL);
+		if (rets && rets != -EBUSY)
+			return rets;
+		return 1;
+	}
+
 	if (mei_cl_is_single_recv_buf(cl)) {
 		if (cl->me_cl->mei_flow_ctrl_creds > 0)
 			return 1;
@@ -1136,6 +1165,9 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
 	if (WARN_ON(!cl || !cl->me_cl))
 		return -EINVAL;
 
+	if (mei_cl_is_fixed_address(cl))
+		return 0;
+
 	if (mei_cl_is_single_recv_buf(cl)) {
 		if (WARN_ON(cl->me_cl->mei_flow_ctrl_creds <= 0))
 			return -EINVAL;
@@ -1179,21 +1211,25 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
 		cl_err(dev, cl, "no such me client\n");
 		return  -ENOTTY;
 	}
+
 	/* always allocate at least client max message */
 	length = max_t(size_t, length, mei_cl_mtu(cl));
+	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
+	if (!cb)
+		return -ENOMEM;
+
+	if (mei_cl_is_fixed_address(cl)) {
+		list_add_tail(&cb->list, &cl->rd_pending);
+		return 0;
+	}
 
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
 		pm_runtime_put_noidle(dev->dev);
 		cl_err(dev, cl, "rpm: get failed %d\n", rets);
-		return rets;
+		goto nortpm;
 	}
 
-	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
-	rets = cb ? 0 : -ENOMEM;
-	if (rets)
-		goto out;
-
 	if (mei_hbuf_acquire(dev)) {
 		rets = mei_hbm_cl_flow_control_req(dev, cl);
 		if (rets < 0)
@@ -1201,6 +1237,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
 
 		list_add_tail(&cb->list, &cl->rd_pending);
 	} else {
+		rets = 0;
 		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 	}
 
@@ -1208,7 +1245,7 @@ out:
 	cl_dbg(dev, cl, "rpm: autosuspend\n");
 	pm_runtime_mark_last_busy(dev->dev);
 	pm_runtime_put_autosuspend(dev->dev);
-
+nortpm:
 	if (rets)
 		mei_io_cb_free(cb);
 
@@ -1256,7 +1293,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 	len = buf->size - cb->buf_idx;
 	msg_slots = mei_data2slots(len);
 
-	mei_hdr.host_addr = cl->host_client_id;
+	mei_hdr.host_addr = mei_cl_host_addr(cl);
 	mei_hdr.me_addr = mei_cl_me_id(cl);
 	mei_hdr.reserved = 0;
 	mei_hdr.internal = cb->internal;
@@ -1340,7 +1377,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 	cb->buf_idx = 0;
 	cl->writing_state = MEI_IDLE;
 
-	mei_hdr.host_addr = cl->host_client_id;
+	mei_hdr.host_addr = mei_cl_host_addr(cl);
 	mei_hdr.me_addr = mei_cl_me_id(cl);
 	mei_hdr.reserved = 0;
 	mei_hdr.msg_complete = 0;
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index bba560e325b7..df46f73c0033 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -176,6 +176,18 @@ static inline const uuid_le *mei_cl_uuid(const struct mei_cl *cl)
 	return &cl->me_cl->props.protocol_name;
 }
 
+/**
+ * mei_cl_host_addr - client's host address
+ *
+ * @cl: host client
+ *
+ * Return: 0 for fixed address client, host address for dynamic client
+ */
+static inline u8 mei_cl_host_addr(const struct mei_cl *cl)
+{
+	return  mei_cl_is_fixed_address(cl) ? 0 : cl->host_client_id;
+}
+
 int mei_cl_disconnect(struct mei_cl *cl);
 void mei_cl_set_disconnected(struct mei_cl *cl);
 int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index f620824f7c86..a4f283165a33 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -150,7 +150,7 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
 	memset(cmd, 0, len);
 
 	cmd->hbm_cmd = hbm_cmd;
-	cmd->host_addr = cl->host_client_id;
+	cmd->host_addr = mei_cl_host_addr(cl);
 	cmd->me_addr = mei_cl_me_id(cl);
 }
 
@@ -188,7 +188,7 @@ int mei_hbm_cl_write(struct mei_device *dev,
 static inline
 bool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd)
 {
-	return cl->host_client_id == cmd->host_addr &&
+	return  mei_cl_host_addr(cl) == cmd->host_addr &&
 		mei_cl_me_id(cl) == cmd->me_addr;
 }
 
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 74795676bb3b..3f3405269c39 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -65,7 +65,7 @@ EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
 static inline int mei_cl_hbm_equal(struct mei_cl *cl,
 			struct mei_msg_hdr *mei_hdr)
 {
-	return cl->host_client_id == mei_hdr->host_addr &&
+	return  mei_cl_host_addr(cl) == mei_hdr->host_addr &&
 		mei_cl_me_id(cl) == mei_hdr->me_addr;
 }
 
-- 
1.9.3


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

* [char-misc-next 09/11] mei: connection to fixed address clients from user-space
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
                   ` (6 preceding siblings ...)
  2015-03-26 22:28 ` [char-misc-next 08/11] mei: support for fixed address clients Tomas Winkler
@ 2015-03-26 22:28 ` Tomas Winkler
  2015-03-26 22:28 ` [char-misc-next 10/11] mei: drop iamthif_mtu from device structure Tomas Winkler
  2015-03-26 22:28 ` [char-misc-next 11/11] mei: txe: fix incorrect indentation Tomas Winkler
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:28 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

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

This should be used for debug only.
The feaure is gated by "allow_fixed_address" control exposed in debugfs.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/debugfs.c | 6 ++++++
 drivers/misc/mei/main.c    | 8 +++++++-
 drivers/misc/mei/mei_dev.h | 4 ++++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index 3f6d855a7ecb..3cac3bc82185 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -209,6 +209,12 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
 		dev_err(dev->dev, "devstate: registration failed\n");
 		goto err;
 	}
+	f = debugfs_create_bool("allow_fixed_address", S_IROTH | S_IWOTH, dir,
+				&dev->allow_fixed_address);
+	if (!f) {
+		dev_err(dev->dev, "allow_fixed_address: registration failed\n");
+		goto err;
+	}
 	dev->dbgfs_dir = dir;
 	return 0;
 err:
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index dcaa7658e742..ca128e2aaf10 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -216,6 +216,11 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
 
 	cb = mei_cl_read_cb(cl, file);
 	if (!cb) {
+		if (mei_cl_is_fixed_address(cl) && dev->allow_fixed_address) {
+			cb = mei_cl_read_cb(cl, NULL);
+			if (cb)
+				goto copy_buffer;
+		}
 		rets = 0;
 		goto out;
 	}
@@ -390,7 +395,8 @@ static int mei_ioctl_connect_client(struct file *file,
 
 	/* find ME client we're trying to connect to */
 	me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
-	if (!me_cl || me_cl->props.fixed_address) {
+	if (!me_cl ||
+	    (me_cl->props.fixed_address && !dev->allow_fixed_address)) {
 		dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
 			&data->in_client_uuid);
 		mei_me_cl_put(me_cl);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index f17979c680a9..6cbcb11a6974 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -475,6 +475,8 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @host_clients_map : host clients id pool
  * @me_client_index : last FW client index in enumeration
  *
+ * @allow_fixed_address: allow user space to connect a fixed client
+ *
  * @wd_cl       : watchdog client
  * @wd_state    : watchdog client state
  * @wd_pending  : watchdog command is pending
@@ -566,6 +568,8 @@ struct mei_device {
 	DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
 	unsigned long me_client_index;
 
+	u32 allow_fixed_address;
+
 	struct mei_cl wd_cl;
 	enum mei_wd_states wd_state;
 	bool wd_pending;
-- 
1.9.3


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

* [char-misc-next 10/11] mei: drop iamthif_mtu from device structure
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
                   ` (7 preceding siblings ...)
  2015-03-26 22:28 ` [char-misc-next 09/11] mei: connection to fixed address clients from user-space Tomas Winkler
@ 2015-03-26 22:28 ` Tomas Winkler
  2015-03-26 22:28 ` [char-misc-next 11/11] mei: txe: fix incorrect indentation Tomas Winkler
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:28 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

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

We can receive mtu with one call now, no need to store it.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c  | 9 +--------
 drivers/misc/mei/mei_dev.h | 2 --
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index a0209f02a31a..fd49c8b0fb8a 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -73,12 +73,6 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 
 	mei_cl_init(cl, dev);
 
-	/* Assign iamthif_mtu to the value received from ME  */
-
-	dev->iamthif_mtu = me_cl->props.max_msg_length;
-	dev_dbg(dev->dev, "IAMTHIF_MTU = %d\n", dev->iamthif_mtu);
-
-
 	ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
 	if (ret < 0) {
 		dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
@@ -240,7 +234,6 @@ 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, MEI_FOP_READ, file);
@@ -249,7 +242,7 @@ static int mei_amthif_read_start(struct mei_cl *cl, struct file *file)
 		goto err;
 	}
 
-	rets = mei_io_cb_alloc_buf(cb, length);
+	rets = mei_io_cb_alloc_buf(cb, mei_cl_mtu(cl));
 	if (rets)
 		goto err;
 
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 6cbcb11a6974..5184758643fc 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -489,7 +489,6 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @iamthif_cl  : amthif host client
  * @iamthif_current_cb : amthif current operation callback
  * @iamthif_open_count : number of opened amthif connections
- * @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_state : amthif processor state
@@ -585,7 +584,6 @@ struct mei_device {
 	struct mei_cl iamthif_cl;
 	struct mei_cl_cb *iamthif_current_cb;
 	long iamthif_open_count;
-	int iamthif_mtu;
 	unsigned long iamthif_timer;
 	u32 iamthif_stall_timer;
 	enum iamthif_states iamthif_state;
-- 
1.9.3


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

* [char-misc-next 11/11] mei: txe: fix incorrect indentation
  2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
                   ` (8 preceding siblings ...)
  2015-03-26 22:28 ` [char-misc-next 10/11] mei: drop iamthif_mtu from device structure Tomas Winkler
@ 2015-03-26 22:28 ` Tomas Winkler
  9 siblings, 0 replies; 15+ messages in thread
From: Tomas Winkler @ 2015-03-26 22:28 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

Remove spurious blank

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/pci-txe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index dcfcba44b6f7..0882c0201907 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -338,7 +338,7 @@ static int mei_txe_pm_runtime_suspend(struct device *device)
 	 * However if device is not wakeable we do not enter
 	 * D-low state and we need to keep the interrupt kicking
 	 */
-	 if (!ret && pci_dev_run_wake(pdev))
+	if (!ret && pci_dev_run_wake(pdev))
 		mei_disable_interrupts(dev);
 
 	dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret);
-- 
1.9.3


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

* Re: [char-misc-next 04/11] mei: revamp client disconnection flow
  2015-03-26 22:28 ` [char-misc-next 04/11] mei: revamp client disconnection flow Tomas Winkler
@ 2015-04-03 14:19   ` Greg KH
  2015-04-05 11:00     ` Winkler, Tomas
  0 siblings, 1 reply; 15+ messages in thread
From: Greg KH @ 2015-04-03 14:19 UTC (permalink / raw)
  To: Tomas Winkler; +Cc: arnd, linux-kernel, Alexander Usyskin

On Fri, Mar 27, 2015 at 12:28:00AM +0200, Tomas Winkler wrote:
> Split disconnected state into two parts first reception disconnect
> response from the firmware and second actually setting of disconnected
> state.  Book keeping data are needed for processing and after firmware
> disconnected the client and are cleaned when setting the disconnected
> state in mei_cl_set_disconneted() function.
> Add mei_cl_send_disconnect to reduce code duplication.
> 
> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
> Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
> ---
>  drivers/misc/mei/bus.c       |   2 -
>  drivers/misc/mei/client.c    | 158 +++++++++++++++++++++++++++++++++----------
>  drivers/misc/mei/client.h    |   3 +
>  drivers/misc/mei/hbm.c       |   8 +--
>  drivers/misc/mei/interrupt.c |  46 +------------
>  drivers/misc/mei/main.c      |   9 +--
>  drivers/misc/mei/mei_dev.h   |   3 +-
>  7 files changed, 134 insertions(+), 95 deletions(-)

This patch fails to apply to my tree, so I'm stopping here in applying
the series :(

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

* RE: [char-misc-next 04/11] mei: revamp client disconnection flow
  2015-04-03 14:19   ` Greg KH
@ 2015-04-05 11:00     ` Winkler, Tomas
  2015-04-05 13:18       ` Greg KH
  0 siblings, 1 reply; 15+ messages in thread
From: Winkler, Tomas @ 2015-04-05 11:00 UTC (permalink / raw)
  To: Greg KH; +Cc: arnd, linux-kernel, Usyskin, Alexander

> > ---
> >  drivers/misc/mei/bus.c       |   2 -
> >  drivers/misc/mei/client.c    | 158 +++++++++++++++++++++++++++++++++----
> ------
> >  drivers/misc/mei/client.h    |   3 +
> >  drivers/misc/mei/hbm.c       |   8 +--
> >  drivers/misc/mei/interrupt.c |  46 +------------
> >  drivers/misc/mei/main.c      |   9 +--
> >  drivers/misc/mei/mei_dev.h   |   3 +-
> >  7 files changed, 134 insertions(+), 95 deletions(-)
> 
> This patch fails to apply to my tree, so I'm stopping here in applying
> the series :(


Oops, there is a one line difference between my tree and the upstream, sending v2 rebased over upstream.
Rest of the series should apply seamlessly.

Thanks
Tomas

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

* Re: [char-misc-next 04/11] mei: revamp client disconnection flow
  2015-04-05 11:00     ` Winkler, Tomas
@ 2015-04-05 13:18       ` Greg KH
  2015-04-06 10:19         ` Winkler, Tomas
  0 siblings, 1 reply; 15+ messages in thread
From: Greg KH @ 2015-04-05 13:18 UTC (permalink / raw)
  To: Winkler, Tomas; +Cc: arnd, linux-kernel, Usyskin, Alexander

On Sun, Apr 05, 2015 at 11:00:05AM +0000, Winkler, Tomas wrote:
> > > ---
> > >  drivers/misc/mei/bus.c       |   2 -
> > >  drivers/misc/mei/client.c    | 158 +++++++++++++++++++++++++++++++++----
> > ------
> > >  drivers/misc/mei/client.h    |   3 +
> > >  drivers/misc/mei/hbm.c       |   8 +--
> > >  drivers/misc/mei/interrupt.c |  46 +------------
> > >  drivers/misc/mei/main.c      |   9 +--
> > >  drivers/misc/mei/mei_dev.h   |   3 +-
> > >  7 files changed, 134 insertions(+), 95 deletions(-)
> > 
> > This patch fails to apply to my tree, so I'm stopping here in applying
> > the series :(
> 
> 
> Oops, there is a one line difference between my tree and the upstream, sending v2 rebased over upstream.
> Rest of the series should apply seamlessly.

Can you resend the rest of the series as well?  It's long gone from my
patch queue.

thanks,

greg k-h

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

* RE: [char-misc-next 04/11] mei: revamp client disconnection flow
  2015-04-05 13:18       ` Greg KH
@ 2015-04-06 10:19         ` Winkler, Tomas
  0 siblings, 0 replies; 15+ messages in thread
From: Winkler, Tomas @ 2015-04-06 10:19 UTC (permalink / raw)
  To: Greg KH; +Cc: arnd, linux-kernel, Usyskin, Alexander



> -----Original Message-----
> From: Greg KH [mailto:gregkh@linuxfoundation.org]
> Sent: Sunday, April 05, 2015 16:19
> To: Winkler, Tomas
> Cc: arnd@arndb.de; linux-kernel@vger.kernel.org; Usyskin, Alexander
> Subject: Re: [char-misc-next 04/11] mei: revamp client disconnection flow
> 
> On Sun, Apr 05, 2015 at 11:00:05AM +0000, Winkler, Tomas wrote:
> > > > ---
> > > >  drivers/misc/mei/bus.c       |   2 -
> > > >  drivers/misc/mei/client.c    | 158
> +++++++++++++++++++++++++++++++++----
> > > ------
> > > >  drivers/misc/mei/client.h    |   3 +
> > > >  drivers/misc/mei/hbm.c       |   8 +--
> > > >  drivers/misc/mei/interrupt.c |  46 +------------
> > > >  drivers/misc/mei/main.c      |   9 +--
> > > >  drivers/misc/mei/mei_dev.h   |   3 +-
> > > >  7 files changed, 134 insertions(+), 95 deletions(-)
> > >
> > > This patch fails to apply to my tree, so I'm stopping here in applying
> > > the series :(
> >
> >
> > Oops, there is a one line difference between my tree and the upstream, sending
> v2 rebased over upstream.
> > Rest of the series should apply seamlessly.
> 
> Can you resend the rest of the series as well?  It's long gone from my
> patch queue.

I've resent the remaining patches including this patch.

Thanks
Tomas


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

end of thread, other threads:[~2015-04-06 10:19 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-26 22:27 [char-misc-next 01/11] mei: fix mei_poll operation Tomas Winkler
2015-03-26 22:27 ` [char-misc-next 02/11] mei: use mei_cl_is_connected consistently Tomas Winkler
2015-03-26 22:27 ` [char-misc-next 03/11] mei: replace check for connection instead of transitioning Tomas Winkler
2015-03-26 22:28 ` [char-misc-next 04/11] mei: revamp client disconnection flow Tomas Winkler
2015-04-03 14:19   ` Greg KH
2015-04-05 11:00     ` Winkler, Tomas
2015-04-05 13:18       ` Greg KH
2015-04-06 10:19         ` Winkler, Tomas
2015-03-26 22:28 ` [char-misc-next 05/11] mei: revamp client connection Tomas Winkler
2015-03-26 22:28 ` [char-misc-next 06/11] mei: add a reference from the host client to the me client Tomas Winkler
2015-03-26 22:28 ` [char-misc-next 07/11] mei: fix flow control for single buffer clients Tomas Winkler
2015-03-26 22:28 ` [char-misc-next 08/11] mei: support for fixed address clients Tomas Winkler
2015-03-26 22:28 ` [char-misc-next 09/11] mei: connection to fixed address clients from user-space Tomas Winkler
2015-03-26 22:28 ` [char-misc-next 10/11] mei: drop iamthif_mtu from device structure Tomas Winkler
2015-03-26 22:28 ` [char-misc-next 11/11] mei: txe: fix incorrect indentation 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.