linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [char-misc-next 00/27] mei: fixes, improvements, and cleanups
@ 2016-02-07 21:35 Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 01/27] mei: debugfs: adjust active clients print buffer Tomas Winkler
                   ` (26 more replies)
  0 siblings, 27 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

The series contains:
1. BUS layer fixes
2. debugfs fixes
3. Support for accessing fixed address clients
4. Continuation of dissolving of amthif oddities.
5. Cleanups

Alexander Usyskin (20):
  mei: debugfs: adjust active clients print buffer
  mei: debugfs: allow hbm features list dump in earlier stages
  mei: call stop on failed char device register
  mei: amthif: don't copy from an empty buffer
  mei: amthif: don't drop read packets on timeout
  mei: amthif: allow only one request at a time
  mei: amthif: use rx_wait queue also for amthif client
  mei: amthif: interrupt reader on link reset
  mei: bus: check if the device is enabled before data transfer
  mei: drop superfluous closing bracket from write traces
  mei: wake blocked write on link reset
  mei: clean write queues and wake waiters on disconnect
  mei: discard replies from unconnected fixed address clients
  mei: fill file pointer in read cb for fixed address client
  mei: fixed address clients for the new platforms
  mei: hbm: warn about fw-initiated disconnect
  mei: drop reserved host client ids
  mei: bus: run rescan on me_clients list change
  mei: hbm: send immediate reply flag in enum request
  mei: split amthif client init from end of clients enumeration

Tomas Winkler (7):
  mei: fix possible integer overflow issue
  mei: constify struct file pointer
  mei: rename variable names 'file_object' to fp
  mei: amthif: replace amthif_rd_complete_list with rd_completed
  mei: amthif: drop parameter validation from mei_amthif_write
  mei: bus: fix RX event scheduling
  mei: bus: fix notification event delivery

 drivers/misc/mei/amthif.c    | 130 +++++---------
 drivers/misc/mei/bus-fixup.c |   2 +-
 drivers/misc/mei/bus.c       |  53 +++++-
 drivers/misc/mei/client.c    | 154 +++++++----------
 drivers/misc/mei/client.h    |  23 +--
 drivers/misc/mei/debugfs.c   |  65 +++++--
 drivers/misc/mei/hbm.c       |  24 ++-
 drivers/misc/mei/hw.h        |  32 +++-
 drivers/misc/mei/init.c      |  10 +-
 drivers/misc/mei/interrupt.c |  77 ++++-----
 drivers/misc/mei/main.c      |  50 +++---
 drivers/misc/mei/mei-trace.h |   4 +-
 drivers/misc/mei/mei_dev.h   |  46 ++---
 drivers/misc/mei/pci-me.c    |   4 +-
 drivers/misc/mei/pci-txe.c   |   4 +-
 drivers/misc/mei/wd.c        | 391 +++++++++++++++++++++++++++++++++++++++++++
 16 files changed, 747 insertions(+), 322 deletions(-)
 create mode 100644 drivers/misc/mei/wd.c

-- 
2.4.3

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

* [char-misc-next 01/27] mei: debugfs: adjust active clients print buffer
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 02/27] mei: debugfs: allow hbm features list dump in earlier stages Tomas Winkler
                   ` (25 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

In case of many active host clients clients (41 and more) 1K buffer
is not enough for full information print.
Calculate buffer size according to real clients number.

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

diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index a138d8a27ab5..9f5410b98688 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -50,6 +50,7 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
 	}
 
 	pos += scnprintf(buf + pos, bufsz - pos, HDR);
+#undef HDR
 
 	/*  if the driver is not enabled the list won't be consistent */
 	if (dev->dev_state != MEI_DEV_ENABLED)
@@ -90,23 +91,37 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
 {
 	struct mei_device *dev = fp->private_data;
 	struct mei_cl *cl;
-	const size_t bufsz = 1024;
+	size_t bufsz = 1;
 	char *buf;
 	int i = 0;
 	int pos = 0;
 	int ret;
 
+#define HDR "   |me|host|state|rd|wr|\n"
+
 	if (!dev)
 		return -ENODEV;
 
+	mutex_lock(&dev->device_lock);
+
+	/*
+	 * if the driver is not enabled the list won't be consistent,
+	 * we output empty table
+	 */
+	if (dev->dev_state == MEI_DEV_ENABLED)
+		list_for_each_entry(cl, &dev->file_list, link)
+			bufsz++;
+
+	bufsz *= sizeof(HDR) + 1;
+
 	buf = kzalloc(bufsz, GFP_KERNEL);
-	if  (!buf)
+	if  (!buf) {
+		mutex_unlock(&dev->device_lock);
 		return -ENOMEM;
+	}
 
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"  |me|host|state|rd|wr|\n");
-
-	mutex_lock(&dev->device_lock);
+	pos += scnprintf(buf + pos, bufsz - pos, HDR);
+#undef HDR
 
 	/*  if the driver is not enabled the list won't be consistent */
 	if (dev->dev_state != MEI_DEV_ENABLED)
@@ -115,7 +130,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
 	list_for_each_entry(cl, &dev->file_list, link) {
 
 		pos += scnprintf(buf + pos, bufsz - pos,
-			"%2d|%2d|%4d|%5d|%2d|%2d|\n",
+			"%3d|%2d|%4d|%5d|%2d|%2d|\n",
 			i, mei_cl_me_id(cl), cl->host_client_id, cl->state,
 			!list_empty(&cl->rd_completed), cl->writing_state);
 		i++;
-- 
2.4.3

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

* [char-misc-next 02/27] mei: debugfs: allow hbm features list dump in earlier stages
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 01/27] mei: debugfs: adjust active clients print buffer Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 03/27] mei: fix possible integer overflow issue Tomas Winkler
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

HBM features list is ready while sending enumerate request and
enumerating clients, output it to debugfs in these states too.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/debugfs.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index 9f5410b98688..6bdd75424fe8 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -165,7 +165,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
 	pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n",
 			mei_hbm_state_str(dev->hbm_state));
 
-	if (dev->hbm_state == MEI_HBM_STARTED) {
+	if (dev->hbm_state >= MEI_HBM_ENUM_CLIENTS &&
+	    dev->hbm_state <= MEI_HBM_STARTED) {
 		pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n");
 		pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n",
 				 dev->hbm_f_pg_supported);
-- 
2.4.3

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

* [char-misc-next 03/27] mei: fix possible integer overflow issue
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 01/27] mei: debugfs: adjust active clients print buffer Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 02/27] mei: debugfs: allow hbm features list dump in earlier stages Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 04/27] mei: call stop on failed char device register Tomas Winkler
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

There is a possible integer overflow following by a buffer overflow
when accumulating messages coming from the FW to compose a full payload.
Occurrence of wrap around has to be prevented for next message size
calculation.
For unsigned integer the addition overflow has occurred when the
result is smaller than one of the arguments.
To simplify the fix, the types of buf.size and buf_idx are set to the
same width, namely size_t also to be aligned with the type of length
parameter in file read/write ops.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/amthif.c    |  5 ++---
 drivers/misc/mei/client.c    |  2 +-
 drivers/misc/mei/interrupt.c | 21 ++++++++++++++++-----
 drivers/misc/mei/main.c      |  5 +++--
 drivers/misc/mei/mei_dev.h   |  4 ++--
 5 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index cd0403f09267..b753df98b476 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -195,9 +195,8 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 		 * remove message from deletion list
 		 */
 
-	dev_dbg(dev->dev, "amthif cb->buf size - %d\n",
-	    cb->buf.size);
-	dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
+	dev_dbg(dev->dev, "amthif cb->buf.size - %zd cb->buf_idx - %zd\n",
+		cb->buf.size, cb->buf_idx);
 
 	/* length is being truncated to PAGE_SIZE, however,
 	 * the buf_idx may point beyond */
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index e069fcaed7aa..738f3d703323 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1569,7 +1569,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 		return 0;
 	}
 
-	cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
+	cl_dbg(dev, cl, "buf: size = %zd idx = %zd\n",
 			cb->buf.size, cb->buf_idx);
 
 	rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 6340dee33052..b8aa047ec258 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -104,6 +104,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 	struct mei_device *dev = cl->dev;
 	struct mei_cl_cb *cb;
 	unsigned char *buffer = NULL;
+	size_t buf_sz;
 
 	cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list);
 	if (!cb) {
@@ -124,11 +125,21 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 		goto out;
 	}
 
-	if (cb->buf.size < mei_hdr->length + cb->buf_idx) {
-		cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n",
+	buf_sz = mei_hdr->length + cb->buf_idx;
+	/* catch for integer overflow */
+	if (buf_sz < cb->buf_idx) {
+		cl_err(dev, cl, "message is too big len %d idx %ld\n",
+		       mei_hdr->length, cb->buf_idx);
+
+		list_move_tail(&cb->list, &complete_list->list);
+		cb->status = -EMSGSIZE;
+		goto out;
+	}
+
+	if (cb->buf.size < buf_sz) {
+		cl_dbg(dev, cl, "message overflow. size %zd len %d idx %zd\n",
 			cb->buf.size, mei_hdr->length, cb->buf_idx);
-		buffer = krealloc(cb->buf.data, mei_hdr->length + cb->buf_idx,
-				  GFP_KERNEL);
+		buffer = krealloc(cb->buf.data, buf_sz, GFP_KERNEL);
 
 		if (!buffer) {
 			cb->status = -ENOMEM;
@@ -136,7 +147,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 			goto out;
 		}
 		cb->buf.data = buffer;
-		cb->buf.size = mei_hdr->length + cb->buf_idx;
+		cb->buf.size = buf_sz;
 	}
 
 	buffer = cb->buf.data + cb->buf_idx;
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 55ae4789c439..5c530bab97f1 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -226,7 +226,7 @@ copy_buffer:
 		goto free;
 	}
 
-	cl_dbg(dev, cl, "buf.size = %d buf.idx = %ld offset = %lld\n",
+	cl_dbg(dev, cl, "buf.size = %zd buf.idx = %zd offset = %lld\n",
 	       cb->buf.size, cb->buf_idx, *offset);
 	if (*offset >= cb->buf_idx) {
 		rets = 0;
@@ -245,7 +245,8 @@ copy_buffer:
 
 	rets = length;
 	*offset += length;
-	if ((unsigned long)*offset < cb->buf_idx)
+	/* not all data was read, keep the cb */
+	if (*offset < cb->buf_idx)
 		goto out;
 
 free:
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index da613268480c..9b793f87b7d4 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -126,7 +126,7 @@ enum mei_cb_file_ops {
  * Intel MEI message data struct
  */
 struct mei_msg_data {
-	u32 size;
+	size_t size;
 	unsigned char *data;
 };
 
@@ -190,7 +190,7 @@ struct mei_cl_cb {
 	struct mei_cl *cl;
 	enum mei_cb_file_ops fop_type;
 	struct mei_msg_data buf;
-	unsigned long buf_idx;
+	size_t buf_idx;
 	unsigned long read_time;
 	struct file *file_object;
 	int status;
-- 
2.4.3

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

* [char-misc-next 04/27] mei: call stop on failed char device register
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (2 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 03/27] mei: fix possible integer overflow issue Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 05/27] mei: amthif: don't copy from an empty buffer Tomas Winkler
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

If registering of character device failed stop the device properly.

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

diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 75fc9c688df8..996344f6c32d 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -210,7 +210,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	err = mei_register(dev, &pdev->dev);
 	if (err)
-		goto release_irq;
+		goto stop;
 
 	pci_set_drvdata(pdev, dev);
 
@@ -231,6 +231,8 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	return 0;
 
+stop:
+	mei_stop(dev);
 release_irq:
 	mei_cancel_work(dev);
 	mei_disable_interrupts(dev);
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index 71f8a7475717..30cc30683c07 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -154,7 +154,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	err = mei_register(dev, &pdev->dev);
 	if (err)
-		goto release_irq;
+		goto stop;
 
 	pci_set_drvdata(pdev, dev);
 
@@ -170,6 +170,8 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	return 0;
 
+stop:
+	mei_stop(dev);
 release_irq:
 
 	mei_cancel_work(dev);
-- 
2.4.3

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

* [char-misc-next 05/27] mei: amthif: don't copy from an empty buffer
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (3 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 04/27] mei: call stop on failed char device register Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 06/27] mei: amthif: don't drop read packets on timeout Tomas Winkler
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

If empty message come from FW (buf_idx == 0) then the current code will
still try to copy data from not filled buffer to the user-space,
instead the code should behave the same as when end of a message
has been reached, clean resources and return 0

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

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index b753df98b476..c3f514027c80 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -185,7 +185,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 	/* if the whole message will fit remove it from the list */
 	if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
 		list_del_init(&cb->list);
-	else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
+	else if (cb->buf_idx <= *offset) {
 		/* end of the message has been reached */
 		list_del_init(&cb->list);
 		rets = 0;
-- 
2.4.3

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

* [char-misc-next 06/27] mei: amthif: don't drop read packets on timeout
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (4 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 05/27] mei: amthif: don't copy from an empty buffer Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 07/27] mei: constify struct file pointer Tomas Winkler
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

Since the driver now uses a list for storing read packets instead of
single variable a pending read is no longer blocking other connections.
A pending read will be discarded up the file closure.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c    | 27 ---------------------------
 drivers/misc/mei/hw.h        |  1 -
 drivers/misc/mei/interrupt.c | 32 --------------------------------
 drivers/misc/mei/main.c      | 16 ----------------
 drivers/misc/mei/mei_dev.h   |  4 ----
 5 files changed, 80 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index c3f514027c80..5da1654bc209 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -50,7 +50,6 @@ void mei_amthif_reset_params(struct mei_device *dev)
 	dev->iamthif_current_cb = NULL;
 	dev->iamthif_canceled = false;
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
-	dev->iamthif_timer = 0;
 	dev->iamthif_stall_timer = 0;
 	dev->iamthif_open_count = 0;
 }
@@ -124,18 +123,10 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 int mei_amthif_read(struct mei_device *dev, struct file *file,
 	       char __user *ubuf, size_t length, loff_t *offset)
 {
-	struct mei_cl *cl = file->private_data;
 	struct mei_cl_cb *cb;
-	unsigned long timeout;
 	int rets;
 	int wait_ret;
 
-	/* Only possible if we are in timeout */
-	if (!cl) {
-		dev_err(dev->dev, "bad file ext.\n");
-		return -ETIME;
-	}
-
 	dev_dbg(dev->dev, "checking amthif data\n");
 	cb = mei_amthif_find_read_list_entry(dev, file);
 
@@ -168,20 +159,6 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 	}
 
 	dev_dbg(dev->dev, "Got amthif data\n");
-	dev->iamthif_timer = 0;
-
-	timeout = cb->read_time +
-		mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
-	dev_dbg(dev->dev, "amthif timeout = %lud\n",
-			timeout);
-
-	if  (time_after(jiffies, timeout)) {
-		dev_dbg(dev->dev, "amthif Time out\n");
-		/* 15 sec for the message has expired */
-		list_del_init(&cb->list);
-		rets = -ETIME;
-		goto free;
-	}
 	/* if the whole message will fit remove it from the list */
 	if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
 		list_del_init(&cb->list);
@@ -303,7 +280,6 @@ int mei_amthif_run_next_cmd(struct mei_device *dev)
 
 	dev->iamthif_canceled = false;
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
-	dev->iamthif_timer = 0;
 	dev->iamthif_file_object = NULL;
 
 	dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
@@ -462,9 +438,6 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
 		dev->iamthif_stall_timer = 0;
 		list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
 		dev_dbg(dev->dev, "amthif read completed\n");
-		dev->iamthif_timer = jiffies;
-		dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
-			dev->iamthif_timer);
 	} else {
 		mei_amthif_run_next_cmd(dev);
 	}
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 4cebde85924f..4c5d6cfd79b4 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -29,7 +29,6 @@
 #define MEI_CLIENTS_INIT_TIMEOUT   15  /* HPS: Clients Enumeration Timeout */
 
 #define MEI_IAMTHIF_STALL_TIMER    12  /* HPS */
-#define MEI_IAMTHIF_READ_TIMER     10  /* HPS */
 
 #define MEI_PGI_TIMEOUT             1  /* PG Isolation time response 1 sec */
 #define MEI_D0I3_TIMEOUT            5  /* D0i3 set/unset max response time */
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index b8aa047ec258..78978193d19b 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -156,7 +156,6 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 	cb->buf_idx += mei_hdr->length;
 
 	if (mei_hdr->msg_complete) {
-		cb->read_time = jiffies;
 		cl_dbg(dev, cl, "completed read length = %lu\n", cb->buf_idx);
 		list_move_tail(&cb->list, &complete_list->list);
 	} else {
@@ -458,7 +457,6 @@ static void mei_connect_timeout(struct mei_cl *cl)
  */
 void mei_timer(struct work_struct *work)
 {
-	unsigned long timeout;
 	struct mei_cl *cl;
 
 	struct mei_device *dev = container_of(work,
@@ -504,7 +502,6 @@ void mei_timer(struct work_struct *work)
 			mei_reset(dev);
 			dev->iamthif_canceled = false;
 			dev->iamthif_state = MEI_IAMTHIF_IDLE;
-			dev->iamthif_timer = 0;
 
 			mei_io_cb_free(dev->iamthif_current_cb);
 			dev->iamthif_current_cb = NULL;
@@ -514,35 +511,6 @@ void mei_timer(struct work_struct *work)
 		}
 	}
 
-	if (dev->iamthif_timer) {
-
-		timeout = dev->iamthif_timer +
-			mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
-
-		dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
-				dev->iamthif_timer);
-		dev_dbg(dev->dev, "timeout = %ld\n", timeout);
-		dev_dbg(dev->dev, "jiffies = %ld\n", jiffies);
-		if (time_after(jiffies, timeout)) {
-			/*
-			 * User didn't read the AMTHI data on time (15sec)
-			 * freeing AMTHI for other requests
-			 */
-
-			dev_dbg(dev->dev, "freeing AMTHI for other requests\n");
-
-			mei_io_list_flush(&dev->amthif_rd_complete_list,
-				&dev->iamthif_cl);
-			mei_io_cb_free(dev->iamthif_current_cb);
-			dev->iamthif_current_cb = NULL;
-
-			dev->iamthif_file_object->private_data = NULL;
-			dev->iamthif_file_object = NULL;
-			dev->iamthif_timer = 0;
-			mei_amthif_run_next_cmd(dev);
-
-		}
-	}
 out:
 	if (dev->dev_state != MEI_DEV_DISABLED)
 		schedule_delayed_work(&dev->timer_work, 2 * HZ);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 5c530bab97f1..384abf0c7395 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -274,7 +274,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 	struct mei_cl *cl = file->private_data;
 	struct mei_cl_cb *write_cb = NULL;
 	struct mei_device *dev;
-	unsigned long timeout = 0;
 	int rets;
 
 	if (WARN_ON(!cl || !cl->dev))
@@ -310,21 +309,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 		goto out;
 	}
 
-	if (cl == &dev->iamthif_cl) {
-		write_cb = mei_amthif_find_read_list_entry(dev, file);
-
-		if (write_cb) {
-			timeout = write_cb->read_time +
-				mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
-
-			if (time_after(jiffies, timeout)) {
-				*offset = 0;
-				mei_io_cb_free(write_cb);
-				write_cb = NULL;
-			}
-		}
-	}
-
 	*offset = 0;
 	write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
 	if (!write_cb) {
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 9b793f87b7d4..4d0e066703ef 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -179,7 +179,6 @@ struct mei_cl;
  * @fop_type: file operation type
  * @buf: buffer for data associated with the callback
  * @buf_idx: last read index
- * @read_time: last read operation time stamp (iamthif)
  * @file_object: pointer to file structure
  * @status: io status of the cb
  * @internal: communication between driver and FW flag
@@ -191,7 +190,6 @@ struct mei_cl_cb {
 	enum mei_cb_file_ops fop_type;
 	struct mei_msg_data buf;
 	size_t buf_idx;
-	unsigned long read_time;
 	struct file *file_object;
 	int status;
 	u32 internal:1;
@@ -413,7 +411,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_timer : time stamp of current amthif command completion
  * @iamthif_stall_timer : timer to detect amthif hang
  * @iamthif_state : amthif processor state
  * @iamthif_canceled : current amthif command is canceled
@@ -504,7 +501,6 @@ struct mei_device {
 	struct mei_cl iamthif_cl;
 	struct mei_cl_cb *iamthif_current_cb;
 	long iamthif_open_count;
-	unsigned long iamthif_timer;
 	u32 iamthif_stall_timer;
 	enum iamthif_states iamthif_state;
 	bool iamthif_canceled;
-- 
2.4.3

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

* [char-misc-next 07/27] mei: constify struct file pointer
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (5 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 06/27] mei: amthif: don't drop read packets on timeout Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 08/27] mei: rename variable names 'file_object' to fp Tomas Winkler
                   ` (19 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

The struct file file pointer is used as an opaque handle to for a
connected client, for this part the pointer should be immutable and
should be set to count.

Reviewed-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c  |  6 +++---
 drivers/misc/mei/client.c  | 12 +++++++-----
 drivers/misc/mei/client.h  | 12 +++++++-----
 drivers/misc/mei/main.c    |  4 ++--
 drivers/misc/mei/mei_dev.h |  6 +++---
 5 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 5da1654bc209..16cceedeed97 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -93,7 +93,7 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
  * Return:   returned a list entry on success, NULL on failure.
  */
 struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
-						struct file *file)
+						  const struct file *file)
 {
 	struct mei_cl_cb *cb;
 
@@ -205,7 +205,7 @@ out:
  *
  * Return: 0 on success, <0 on failure.
  */
-static int mei_amthif_read_start(struct mei_cl *cl, struct file *file)
+static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file)
 {
 	struct mei_device *dev = cl->dev;
 	struct mei_cl_cb *cb;
@@ -495,7 +495,7 @@ static bool mei_clear_list(struct mei_device *dev,
  *
  * Return: true if callback removed from the list, false otherwise
  */
-static bool mei_clear_lists(struct mei_device *dev, struct file *file)
+static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
 {
 	bool removed = false;
 
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 738f3d703323..4c23caee04ab 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -359,7 +359,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
  * Return: mei_cl_cb pointer or NULL;
  */
 struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
-				 struct file *fp)
+				 const struct file *fp)
 {
 	struct mei_cl_cb *cb;
 
@@ -455,7 +455,8 @@ int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
  * Return: cb on success and NULL on failure
  */
 struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
-				  enum mei_cb_file_ops type, struct file *fp)
+				  enum mei_cb_file_ops type,
+				  const struct file *fp)
 {
 	struct mei_cl_cb *cb;
 
@@ -1028,7 +1029,7 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
  * Return: 0 on success, <0 on failure.
  */
 int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
-		   struct file *file)
+		  const struct file *file)
 {
 	struct mei_device *dev;
 	struct mei_cl_cb *cb;
@@ -1277,7 +1278,8 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * Return: 0 on such and error otherwise.
  */
-int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request)
+int mei_cl_notify_request(struct mei_cl *cl,
+			  const struct file *file, u8 request)
 {
 	struct mei_device *dev;
 	struct mei_cl_cb *cb;
@@ -1443,7 +1445,7 @@ static bool mei_cl_is_read_fc_cb(struct mei_cl *cl)
  *
  * Return: 0 on success, <0 on failure.
  */
-int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
+int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
 {
 	struct mei_device *dev;
 	struct mei_cl_cb *cb;
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 2e90a25f896e..fdc43279368f 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -83,7 +83,7 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl)
  * MEI IO Functions
  */
 struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
-				 struct file *fp);
+				 const struct file *fp);
 void mei_io_cb_free(struct mei_cl_cb *priv_cb);
 int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length);
 
@@ -116,7 +116,8 @@ struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl,
 				 const struct file *fp);
 void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp);
 struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
-				  enum mei_cb_file_ops type, struct file *fp);
+				  enum mei_cb_file_ops type,
+				  const struct file *fp);
 int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp);
 
 /*
@@ -213,10 +214,10 @@ 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 mei_me_client *me_cl,
-		   struct file *file);
+		   const 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_read_start(struct mei_cl *cl, size_t length, const struct file *fp);
 int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr,
 			struct mei_cl_cb *cmpl_list);
 int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
@@ -229,7 +230,8 @@ void mei_host_client_init(struct work_struct *work);
 
 u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop);
 enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request);
-int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request);
+int mei_cl_notify_request(struct mei_cl *cl,
+			  const struct file *file, u8 request);
 int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
 		      struct mei_cl_cb *cmpl_list);
 int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 384abf0c7395..ba9790ead256 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -435,7 +435,7 @@ end:
  *
  * Return: 0 on success , <0 on error
  */
-static int mei_ioctl_client_notify_request(struct file *file, u32 request)
+static int mei_ioctl_client_notify_request(const struct file *file, u32 request)
 {
 	struct mei_cl *cl = file->private_data;
 
@@ -454,7 +454,7 @@ static int mei_ioctl_client_notify_request(struct file *file, u32 request)
  *
  * Return: 0 on success , <0 on error
  */
-static int mei_ioctl_client_notify_get(struct file *file, u32 *notify_get)
+static int mei_ioctl_client_notify_get(const struct file *file, u32 *notify_get)
 {
 	struct mei_cl *cl = file->private_data;
 	bool notify_ev;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 4d0e066703ef..947e0a70577a 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -190,7 +190,7 @@ struct mei_cl_cb {
 	enum mei_cb_file_ops fop_type;
 	struct mei_msg_data buf;
 	size_t buf_idx;
-	struct file *file_object;
+	const struct file *file_object;
 	int status;
 	u32 internal:1;
 	u32 completed:1;
@@ -497,7 +497,7 @@ struct mei_device {
 	struct mei_cl_cb amthif_cmd_list;
 	/* driver managed amthif list for reading completed amthif cmd data */
 	struct mei_cl_cb amthif_rd_complete_list;
-	struct file *iamthif_file_object;
+	const struct file *iamthif_file_object;
 	struct mei_cl iamthif_cl;
 	struct mei_cl_cb *iamthif_current_cb;
 	long iamthif_open_count;
@@ -590,7 +590,7 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
 int mei_amthif_release(struct mei_device *dev, struct file *file);
 
 struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
-						struct file *file);
+						  const struct file *file);
 
 int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb);
 int mei_amthif_run_next_cmd(struct mei_device *dev);
-- 
2.4.3

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

* [char-misc-next 08/27] mei: rename variable names 'file_object' to fp
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (6 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 07/27] mei: constify struct file pointer Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 09/27] mei: amthif: allow only one request at a time Tomas Winkler
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

The driver uses three names file, fp, and file_object for
struct file type. To improve code clarity and adjust to my taste
rename file_object to more common and shorter fp.

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

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 16cceedeed97..647edc68884f 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -98,7 +98,7 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 	struct mei_cl_cb *cb;
 
 	list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
-		if (cb->file_object == file)
+		if (cb->fp == file)
 			return cb;
 	return NULL;
 }
@@ -224,7 +224,7 @@ static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file)
 	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 
 	dev->iamthif_state = MEI_IAMTHIF_READING;
-	dev->iamthif_file_object = cb->file_object;
+	dev->iamthif_fp = cb->fp;
 	dev->iamthif_current_cb = cb;
 
 	return 0;
@@ -253,7 +253,7 @@ static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
 
 	dev->iamthif_state = MEI_IAMTHIF_WRITING;
 	dev->iamthif_current_cb = cb;
-	dev->iamthif_file_object = cb->file_object;
+	dev->iamthif_fp = cb->fp;
 	dev->iamthif_canceled = false;
 
 	ret = mei_cl_write(cl, cb, false);
@@ -261,7 +261,7 @@ static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
 		return ret;
 
 	if (cb->completed)
-		cb->status = mei_amthif_read_start(cl, cb->file_object);
+		cb->status = mei_amthif_read_start(cl, cb->fp);
 
 	return 0;
 }
@@ -280,7 +280,7 @@ int mei_amthif_run_next_cmd(struct mei_device *dev)
 
 	dev->iamthif_canceled = false;
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
-	dev->iamthif_file_object = NULL;
+	dev->iamthif_fp = NULL;
 
 	dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
 
@@ -338,7 +338,7 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
 	poll_wait(file, &dev->iamthif_cl.wait, wait);
 
 	if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
-	    dev->iamthif_file_object == file) {
+	    dev->iamthif_fp == file) {
 
 		mask |= POLLIN | POLLRDNORM;
 		mei_amthif_run_next_cmd(dev);
@@ -368,7 +368,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 		return ret;
 
 	if (cb->completed)
-		cb->status = mei_amthif_read_start(cl, cb->file_object);
+		cb->status = mei_amthif_read_start(cl, cb->fp);
 
 	return 0;
 }
@@ -469,7 +469,7 @@ static bool mei_clear_list(struct mei_device *dev,
 	/* list all list member */
 	list_for_each_entry_safe(cb, next, mei_cb_list, list) {
 		/* check if list member associated with a file */
-		if (file == cb->file_object) {
+		if (file == cb->fp) {
 			/* check if cb equal to current iamthif cb */
 			if (dev->iamthif_current_cb == cb) {
 				dev->iamthif_current_cb = NULL;
@@ -518,7 +518,7 @@ static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
 	/* check if iamthif_current_cb not NULL */
 	if (dev->iamthif_current_cb && !removed) {
 		/* check file and iamthif current cb association */
-		if (dev->iamthif_current_cb->file_object == file) {
+		if (dev->iamthif_current_cb->fp == file) {
 			/* remove cb */
 			mei_io_cb_free(dev->iamthif_current_cb);
 			dev->iamthif_current_cb = NULL;
@@ -541,7 +541,7 @@ int mei_amthif_release(struct mei_device *dev, struct file *file)
 	if (dev->iamthif_open_count > 0)
 		dev->iamthif_open_count--;
 
-	if (dev->iamthif_file_object == file &&
+	if (dev->iamthif_fp == file &&
 	    dev->iamthif_state != MEI_IAMTHIF_IDLE) {
 
 		dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 4c23caee04ab..c57ac25ce8db 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -368,7 +368,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
 		return NULL;
 
 	INIT_LIST_HEAD(&cb->list);
-	cb->file_object = fp;
+	cb->fp = fp;
 	cb->cl = cl;
 	cb->buf_idx = 0;
 	cb->fop_type = type;
@@ -486,7 +486,7 @@ struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp)
 	struct mei_cl_cb *cb;
 
 	list_for_each_entry(cb, &cl->rd_completed, list)
-		if (!fp || fp == cb->file_object)
+		if (!fp || fp == cb->fp)
 			return cb;
 
 	return NULL;
@@ -504,12 +504,12 @@ void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp)
 	struct mei_cl_cb *cb, *next;
 
 	list_for_each_entry_safe(cb, next, &cl->rd_completed, list)
-		if (!fp || fp == cb->file_object)
+		if (!fp || fp == cb->fp)
 			mei_io_cb_free(cb);
 
 
 	list_for_each_entry_safe(cb, next, &cl->rd_pending, list)
-		if (!fp || fp == cb->file_object)
+		if (!fp || fp == cb->fp)
 			mei_io_cb_free(cb);
 }
 
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 78978193d19b..37c8f0e14387 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -506,7 +506,7 @@ void mei_timer(struct work_struct *work)
 			mei_io_cb_free(dev->iamthif_current_cb);
 			dev->iamthif_current_cb = NULL;
 
-			dev->iamthif_file_object = NULL;
+			dev->iamthif_fp = NULL;
 			mei_amthif_run_next_cmd(dev);
 		}
 	}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 947e0a70577a..3acbbb49d08c 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -179,7 +179,7 @@ struct mei_cl;
  * @fop_type: file operation type
  * @buf: buffer for data associated with the callback
  * @buf_idx: last read index
- * @file_object: pointer to file structure
+ * @fp: pointer to file structure
  * @status: io status of the cb
  * @internal: communication between driver and FW flag
  * @completed: the transfer or reception has completed
@@ -190,7 +190,7 @@ struct mei_cl_cb {
 	enum mei_cb_file_ops fop_type;
 	struct mei_msg_data buf;
 	size_t buf_idx;
-	const struct file *file_object;
+	const struct file *fp;
 	int status;
 	u32 internal:1;
 	u32 completed:1;
@@ -407,7 +407,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  *
  * @amthif_cmd_list : amthif list for cmd waiting
  * @amthif_rd_complete_list : amthif list for reading completed cmd data
- * @iamthif_file_object : file for current amthif operation
+ * @iamthif_fp : file for current amthif operation
  * @iamthif_cl  : amthif host client
  * @iamthif_current_cb : amthif current operation callback
  * @iamthif_open_count : number of opened amthif connections
@@ -497,7 +497,7 @@ struct mei_device {
 	struct mei_cl_cb amthif_cmd_list;
 	/* driver managed amthif list for reading completed amthif cmd data */
 	struct mei_cl_cb amthif_rd_complete_list;
-	const struct file *iamthif_file_object;
+	const struct file *iamthif_fp;
 	struct mei_cl iamthif_cl;
 	struct mei_cl_cb *iamthif_current_cb;
 	long iamthif_open_count;
-- 
2.4.3

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

* [char-misc-next 09/27] mei: amthif: allow only one request at a time
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (7 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 08/27] mei: rename variable names 'file_object' to fp Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 10/27] mei: amthif: replace amthif_rd_complete_list with rd_completed Tomas Winkler
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

A next amthif write can be executed only after the previous one has
completed.

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

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 647edc68884f..4383a9ad9208 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -315,6 +315,14 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
 	dev = cl->dev;
 
 	list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
+
+	/*
+	 * The previous request is still in processing, queue this one.
+	 */
+	if (dev->iamthif_state > MEI_IAMTHIF_IDLE &&
+	    dev->iamthif_state < MEI_IAMTHIF_READ_COMPLETE)
+		return 0;
+
 	return mei_amthif_run_next_cmd(dev);
 }
 
-- 
2.4.3

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

* [char-misc-next 10/27] mei: amthif: replace amthif_rd_complete_list with rd_completed
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (8 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 09/27] mei: amthif: allow only one request at a time Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 11/27] mei: amthif: drop parameter validation from mei_amthif_write Tomas Winkler
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

Now when we have per client rd_completed list we can remove
the amthif specific amthif_rd_complete_list.
In addition in the function mei_amthif_read do not loop over the
rd_completed list like the original code as the code path is unlocked.

Reviewed-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c    | 39 +++++++++++----------------------------
 drivers/misc/mei/client.c    |  1 -
 drivers/misc/mei/init.c      |  1 -
 drivers/misc/mei/interrupt.c |  2 +-
 drivers/misc/mei/mei_dev.h   |  7 +------
 5 files changed, 13 insertions(+), 37 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 4383a9ad9208..058dd6917805 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -85,26 +85,6 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 }
 
 /**
- * mei_amthif_find_read_list_entry - finds a amthilist entry for current file
- *
- * @dev: the device structure
- * @file: pointer to file object
- *
- * Return:   returned a list entry on success, NULL on failure.
- */
-struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
-						  const struct file *file)
-{
-	struct mei_cl_cb *cb;
-
-	list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
-		if (cb->fp == file)
-			return cb;
-	return NULL;
-}
-
-
-/**
  * mei_amthif_read - read data from AMTHIF client
  *
  * @dev: the device structure
@@ -123,12 +103,13 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 int mei_amthif_read(struct mei_device *dev, struct file *file,
 	       char __user *ubuf, size_t length, loff_t *offset)
 {
+	struct mei_cl *cl = file->private_data;
 	struct mei_cl_cb *cb;
 	int rets;
 	int wait_ret;
 
 	dev_dbg(dev->dev, "checking amthif data\n");
-	cb = mei_amthif_find_read_list_entry(dev, file);
+	cb = mei_cl_read_cb(cl, file);
 
 	/* Check for if we can block or not*/
 	if (cb == NULL && file->f_flags & O_NONBLOCK)
@@ -141,7 +122,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 		mutex_unlock(&dev->device_lock);
 
 		wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
-			(cb = mei_amthif_find_read_list_entry(dev, file)));
+					    !list_empty(&cl->rd_completed));
 
 		/* Locking again the Mutex */
 		mutex_lock(&dev->device_lock);
@@ -149,7 +130,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 		if (wait_ret)
 			return -ERESTARTSYS;
 
-		dev_dbg(dev->dev, "woke up from sleep\n");
+		cb = mei_cl_read_cb(cl, file);
 	}
 
 	if (cb->status) {
@@ -420,11 +401,12 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl,
 /**
  * mei_amthif_complete - complete amthif callback.
  *
- * @dev: the device structure.
+ * @cl: host client
  * @cb: callback block.
  */
-void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
+void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 {
+	struct mei_device *dev = cl->dev;
 
 	if (cb->fop_type == MEI_FOP_WRITE) {
 		if (!cb->status) {
@@ -436,7 +418,7 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
 		 * in case of error enqueue the write cb to complete read list
 		 * so it can be propagated to the reader
 		 */
-		list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
+		list_add_tail(&cb->list, &cl->rd_completed);
 		wake_up_interruptible(&dev->iamthif_cl.wait);
 		return;
 	}
@@ -444,7 +426,7 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
 	if (!dev->iamthif_canceled) {
 		dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
 		dev->iamthif_stall_timer = 0;
-		list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
+		list_add_tail(&cb->list, &cl->rd_completed);
 		dev_dbg(dev->dev, "amthif read completed\n");
 	} else {
 		mei_amthif_run_next_cmd(dev);
@@ -506,10 +488,11 @@ static bool mei_clear_list(struct mei_device *dev,
 static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
 {
 	bool removed = false;
+	struct mei_cl *cl = &dev->iamthif_cl;
 
 	/* remove callbacks associated with a file */
 	mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
-	if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list))
+	if (mei_clear_list(dev, file, &cl->rd_completed))
 		removed = true;
 
 	mei_clear_list(dev, file, &dev->ctrl_rd_list.list);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index c57ac25ce8db..32991684563b 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -536,7 +536,6 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
 	mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
 	mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
 	mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
-	mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
 
 	mei_cl_read_cb_flush(cl, fp);
 
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 46a4302e5524..a1d978a82806 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -402,7 +402,6 @@ void mei_device_init(struct mei_device *dev,
 
 	INIT_LIST_HEAD(&dev->iamthif_cl.link);
 	mei_io_list_init(&dev->amthif_cmd_list);
-	mei_io_list_init(&dev->amthif_rd_complete_list);
 
 	bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
 	dev->open_handle_count = 0;
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 37c8f0e14387..72806ef6efdd 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -48,7 +48,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
 
 		dev_dbg(dev->dev, "completing call back.\n");
 		if (cl == &dev->iamthif_cl)
-			mei_amthif_complete(dev, cb);
+			mei_amthif_complete(cl, cb);
 		else
 			mei_cl_complete(cl, cb);
 	}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 3acbbb49d08c..81901967911d 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -406,7 +406,6 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @allow_fixed_address: allow user space to connect a fixed client
  *
  * @amthif_cmd_list : amthif list for cmd waiting
- * @amthif_rd_complete_list : amthif list for reading completed cmd data
  * @iamthif_fp : file for current amthif operation
  * @iamthif_cl  : amthif host client
  * @iamthif_current_cb : amthif current operation callback
@@ -496,7 +495,6 @@ struct mei_device {
 	/* amthif list for cmd waiting */
 	struct mei_cl_cb amthif_cmd_list;
 	/* driver managed amthif list for reading completed amthif cmd data */
-	struct mei_cl_cb amthif_rd_complete_list;
 	const struct file *iamthif_fp;
 	struct mei_cl iamthif_cl;
 	struct mei_cl_cb *iamthif_current_cb;
@@ -589,15 +587,12 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
 
 int mei_amthif_release(struct mei_device *dev, struct file *file);
 
-struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
-						  const struct file *file);
-
 int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb);
 int mei_amthif_run_next_cmd(struct mei_device *dev);
 int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 			struct mei_cl_cb *cmpl_list);
 
-void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
+void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
 int mei_amthif_irq_read_msg(struct mei_cl *cl,
 			    struct mei_msg_hdr *mei_hdr,
 			    struct mei_cl_cb *complete_list);
-- 
2.4.3

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

* [char-misc-next 11/27] mei: amthif: drop parameter validation from mei_amthif_write
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (9 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 10/27] mei: amthif: replace amthif_rd_complete_list with rd_completed Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 12/27] mei: amthif: use rx_wait queue also for amthif client Tomas Winkler
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

Remove duplicated parameter validation from mei_amthif_write functions,
The parameter check is already performed by the caller function
mei_write

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

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 058dd6917805..911b663a8fdb 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -285,15 +285,7 @@ int mei_amthif_run_next_cmd(struct mei_device *dev)
 int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
 {
 
-	struct mei_device *dev;
-
-	if (WARN_ON(!cl || !cl->dev))
-		return -ENODEV;
-
-	if (WARN_ON(!cb))
-		return -EINVAL;
-
-	dev = cl->dev;
+	struct mei_device *dev = cl->dev;
 
 	list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
 
-- 
2.4.3

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

* [char-misc-next 12/27] mei: amthif: use rx_wait queue also for amthif client
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (10 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 11/27] mei: amthif: drop parameter validation from mei_amthif_write Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 13/27] mei: amthif: interrupt reader on link reset Tomas Winkler
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

Switch using cl->rx_wait wait queue also for amthif, there is nothing
special about amthif in that matter in Rx flow.
The cl->wait is reserved for hbm flows and asynchronous events

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

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 911b663a8fdb..b98eac389782 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -121,8 +121,8 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 		/* unlock the Mutex */
 		mutex_unlock(&dev->device_lock);
 
-		wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
-					    !list_empty(&cl->rd_completed));
+		wait_ret = wait_event_interruptible(cl->rx_wait,
+					!list_empty(&cl->rd_completed));
 
 		/* Locking again the Mutex */
 		mutex_lock(&dev->device_lock);
@@ -316,7 +316,7 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
 {
 	unsigned int mask = 0;
 
-	poll_wait(file, &dev->iamthif_cl.wait, wait);
+	poll_wait(file, &dev->iamthif_cl.rx_wait, wait);
 
 	if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
 	    dev->iamthif_fp == file) {
@@ -411,7 +411,7 @@ void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 		 * so it can be propagated to the reader
 		 */
 		list_add_tail(&cb->list, &cl->rd_completed);
-		wake_up_interruptible(&dev->iamthif_cl.wait);
+		wake_up_interruptible(&cl->rx_wait);
 		return;
 	}
 
@@ -425,7 +425,7 @@ void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 	}
 
 	dev_dbg(dev->dev, "completing amthif call back.\n");
-	wake_up_interruptible(&dev->iamthif_cl.wait);
+	wake_up_interruptible(&cl->rx_wait);
 }
 
 /**
-- 
2.4.3

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

* [char-misc-next 13/27] mei: amthif: interrupt reader on link reset
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (11 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 12/27] mei: amthif: use rx_wait queue also for amthif client Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 14/27] mei: bus: fix RX event scheduling Tomas Winkler
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

In case of link reset all waiting readers should be interrupted.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index b98eac389782..ca2efc3602df 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -122,7 +122,8 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 		mutex_unlock(&dev->device_lock);
 
 		wait_ret = wait_event_interruptible(cl->rx_wait,
-					!list_empty(&cl->rd_completed));
+					!list_empty(&cl->rd_completed) ||
+					!mei_cl_is_connected(cl));
 
 		/* Locking again the Mutex */
 		mutex_lock(&dev->device_lock);
@@ -130,6 +131,11 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 		if (wait_ret)
 			return -ERESTARTSYS;
 
+		if (!mei_cl_is_connected(cl)) {
+			rets = -EBUSY;
+			goto out;
+		}
+
 		cb = mei_cl_read_cb(cl, file);
 	}
 
-- 
2.4.3

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

* [char-misc-next 14/27] mei: bus: fix RX event scheduling
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (12 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 13/27] mei: amthif: interrupt reader on link reset Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 15/27] mei: bus: fix notification event delivery Tomas Winkler
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

In this particular case this more correct and safer to check if the RX
event is set in the event mask rather than query waitqueue_active
Since the check is already performed in the mei_cl_bus_rx_event
function,  it is just required to check for its return value.
Second, since we don't have exclusive waiter wake_up_interruptible_all
is not used correctly here.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c     | 13 +++++++++----
 drivers/misc/mei/client.c  |  6 ++----
 drivers/misc/mei/mei_dev.h |  2 +-
 3 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 0b05aa938799..a40d8e24ecda 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -252,23 +252,28 @@ void mei_cl_bus_notify_event(struct mei_cl *cl)
 }
 
 /**
- * mei_cl_bus_rx_event  - schedule rx evenet
+ * mei_cl_bus_rx_event  - schedule rx event
  *
  * @cl: host client
+ *
+ * Return: true if event was scheduled
+ *         false if the client is not waiting for event
  */
-void mei_cl_bus_rx_event(struct mei_cl *cl)
+bool mei_cl_bus_rx_event(struct mei_cl *cl)
 {
 	struct mei_cl_device *cldev = cl->cldev;
 
 	if (!cldev || !cldev->event_cb)
-		return;
+		return false;
 
 	if (!(cldev->events_mask & BIT(MEI_CL_EVENT_RX)))
-		return;
+		return false;
 
 	set_bit(MEI_CL_EVENT_RX, &cldev->events);
 
 	schedule_work(&cldev->event_work);
+
+	return true;
 }
 
 /**
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 32991684563b..574f7394fb2b 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1735,10 +1735,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 
 	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);
+		if (!mei_cl_bus_rx_event(cl))
+			wake_up_interruptible(&cl->rx_wait);
 		break;
 
 	case MEI_FOP_CONNECT:
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 81901967911d..be97b8f2a883 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -316,7 +316,7 @@ void mei_cl_bus_dev_fixup(struct mei_cl_device *dev);
 ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 			bool blocking);
 ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
-void mei_cl_bus_rx_event(struct mei_cl *cl);
+bool mei_cl_bus_rx_event(struct mei_cl *cl);
 void mei_cl_bus_notify_event(struct mei_cl *cl);
 void mei_cl_bus_remove_devices(struct mei_device *bus);
 int mei_cl_bus_init(void);
-- 
2.4.3

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

* [char-misc-next 15/27] mei: bus: fix notification event delivery
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (13 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 14/27] mei: bus: fix RX event scheduling Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 16/27] mei: bus: check if the device is enabled before data transfer Tomas Winkler
                   ` (11 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

Call wake_up cl->ev_wait only in case there is no bus client registered
to the event notification.
Second, since we don't have exclusive waiter wake_up_interruptible_all
is not used correctly here.

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

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index a40d8e24ecda..990f4f65c35e 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -230,25 +230,30 @@ static void mei_cl_bus_event_work(struct work_struct *work)
  * mei_cl_bus_notify_event - schedule notify cb on bus client
  *
  * @cl: host client
+ *
+ * Return: true if event was scheduled
+ *         false if the client is not waiting for event
  */
-void mei_cl_bus_notify_event(struct mei_cl *cl)
+bool mei_cl_bus_notify_event(struct mei_cl *cl)
 {
 	struct mei_cl_device *cldev = cl->cldev;
 
 	if (!cldev || !cldev->event_cb)
-		return;
+		return false;
 
 	if (!(cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)))
-		return;
+		return false;
 
 	if (!cl->notify_ev)
-		return;
+		return false;
 
 	set_bit(MEI_CL_EVENT_NOTIF, &cldev->events);
 
 	schedule_work(&cldev->event_work);
 
 	cl->notify_ev = false;
+
+	return true;
 }
 
 /**
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 574f7394fb2b..3fd070a698ce 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1363,12 +1363,12 @@ void mei_cl_notify(struct mei_cl *cl)
 
 	cl_dbg(dev, cl, "notify event");
 	cl->notify_ev = true;
-	wake_up_interruptible_all(&cl->ev_wait);
+	if (!mei_cl_bus_notify_event(cl))
+		wake_up_interruptible(&cl->ev_wait);
 
 	if (cl->ev_async)
 		kill_fasync(&cl->ev_async, SIGIO, POLL_PRI);
 
-	mei_cl_bus_notify_event(cl);
 }
 
 /**
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index be97b8f2a883..70c4da015401 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -317,7 +317,7 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 			bool blocking);
 ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
 bool mei_cl_bus_rx_event(struct mei_cl *cl);
-void mei_cl_bus_notify_event(struct mei_cl *cl);
+bool mei_cl_bus_notify_event(struct mei_cl *cl);
 void mei_cl_bus_remove_devices(struct mei_device *bus);
 int mei_cl_bus_init(void);
 void mei_cl_bus_exit(void);
-- 
2.4.3

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

* [char-misc-next 16/27] mei: bus: check if the device is enabled before data transfer
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (14 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 15/27] mei: bus: fix notification event delivery Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 17/27] mei: drop superfluous closing bracket from write traces Tomas Winkler
                   ` (10 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, stable, Tomas Winkler

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

The bus data transfer interface was missing the check if the device is
in enabled state, this may lead to stack corruption during link reset.

Cc: <stable@vger.kernel.org> #4.0
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 990f4f65c35e..83b084558ee5 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -53,6 +53,11 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 	bus = cl->dev;
 
 	mutex_lock(&bus->device_lock);
+	if (bus->dev_state != MEI_DEV_ENABLED) {
+		rets = -ENODEV;
+		goto out;
+	}
+
 	if (!mei_cl_is_connected(cl)) {
 		rets = -ENODEV;
 		goto out;
@@ -109,6 +114,10 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
 	bus = cl->dev;
 
 	mutex_lock(&bus->device_lock);
+	if (bus->dev_state != MEI_DEV_ENABLED) {
+		rets = -ENODEV;
+		goto out;
+	}
 
 	cb = mei_cl_read_cb(cl, NULL);
 	if (cb)
-- 
2.4.3

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

* [char-misc-next 17/27] mei: drop superfluous closing bracket from write traces
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (15 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 16/27] mei: bus: check if the device is enabled before data transfer Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 18/27] mei: wake blocked write on link reset Tomas Winkler
                   ` (9 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/mei-trace.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h
index 86e5068837c1..7d2d5d4a1624 100644
--- a/drivers/misc/mei/mei-trace.h
+++ b/drivers/misc/mei/mei-trace.h
@@ -60,7 +60,7 @@ TRACE_EVENT(mei_reg_write,
 		__entry->offs = offs;
 		__entry->val = val;
 	),
-	TP_printk("[%s] write %s[%#x] = %#x)",
+	TP_printk("[%s] write %s[%#x] = %#x",
 		  __get_str(dev), __entry->reg,  __entry->offs, __entry->val)
 );
 
@@ -98,7 +98,7 @@ TRACE_EVENT(mei_pci_cfg_write,
 		__entry->offs = offs;
 		__entry->val = val;
 	),
-	TP_printk("[%s] pci cfg write %s[%#x] = %#x)",
+	TP_printk("[%s] pci cfg write %s[%#x] = %#x",
 		  __get_str(dev), __entry->reg,  __entry->offs, __entry->val)
 );
 
-- 
2.4.3

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

* [char-misc-next 18/27] mei: wake blocked write on link reset
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (16 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 17/27] mei: drop superfluous closing bracket from write traces Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 19/27] mei: clean write queues and wake waiters on disconnect Tomas Winkler
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

In case of link reset all blocked writes should be interrupted.
Note, that currently blocking write is used only through bus layer.

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

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 3fd070a698ce..5ddc690752c2 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1691,7 +1691,8 @@ out:
 
 		mutex_unlock(&dev->device_lock);
 		rets = wait_event_interruptible(cl->tx_wait,
-				cl->writing_state == MEI_WRITE_COMPLETE);
+				cl->writing_state == MEI_WRITE_COMPLETE ||
+				(!mei_cl_is_connected(cl)));
 		mutex_lock(&dev->device_lock);
 		/* wait_event_interruptible returns -ERESTARTSYS */
 		if (rets) {
@@ -1699,6 +1700,10 @@ out:
 				rets = -EINTR;
 			goto err;
 		}
+		if (cl->writing_state != MEI_WRITE_COMPLETE) {
+			rets = -EFAULT;
+			goto err;
+		}
 	}
 
 	rets = size;
-- 
2.4.3

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

* [char-misc-next 19/27] mei: clean write queues and wake waiters on disconnect
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (17 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 18/27] mei: wake blocked write on link reset Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 20/27] mei: discard replies from unconnected fixed address clients Tomas Winkler
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

Clean write and write_waiting queues in disconnect.
Requests in those queues are stale and processing will lead to
fat warnings.

In multi thread operations on disconnect and in FW disconnect case -
write/read/event waiters should end wait and return error.
Wake all waiters for disconnecting client to achieve that.

Drop wake all and write queue clean on reset,
as now we waking all waiters and cleaning write queues on disconnect.
No need to do it twice.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/client.c | 71 ++++++++++++++++++++---------------------------
 drivers/misc/mei/client.h |  2 --
 drivers/misc/mei/init.c   |  5 ----
 3 files changed, 30 insertions(+), 48 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 5ddc690752c2..3a9c656f1425 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -720,6 +720,33 @@ bool mei_hbuf_acquire(struct mei_device *dev)
 }
 
 /**
+ * mei_cl_wake_all - wake up readers, writers and event waiters so
+ *                 they can be interrupted
+ *
+ * @cl: host client
+ */
+static void mei_cl_wake_all(struct mei_cl *cl)
+{
+	struct mei_device *dev = cl->dev;
+
+	/* synchronized under device mutex */
+	if (waitqueue_active(&cl->rx_wait)) {
+		cl_dbg(dev, cl, "Waking up reading client!\n");
+		wake_up_interruptible(&cl->rx_wait);
+	}
+	/* synchronized under device mutex */
+	if (waitqueue_active(&cl->tx_wait)) {
+		cl_dbg(dev, cl, "Waking up writing client!\n");
+		wake_up_interruptible(&cl->tx_wait);
+	}
+	/* synchronized under device mutex */
+	if (waitqueue_active(&cl->ev_wait)) {
+		cl_dbg(dev, cl, "Waking up waiting for event clients!\n");
+		wake_up_interruptible(&cl->ev_wait);
+	}
+}
+
+/**
  * mei_cl_set_disconnected - set disconnected state and clear
  *   associated states and resources
  *
@@ -734,8 +761,11 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
 		return;
 
 	cl->state = MEI_FILE_DISCONNECTED;
+	mei_io_list_free(&dev->write_list, cl);
+	mei_io_list_free(&dev->write_waiting_list, cl);
 	mei_io_list_flush(&dev->ctrl_rd_list, cl);
 	mei_io_list_flush(&dev->ctrl_wr_list, cl);
+	mei_cl_wake_all(cl);
 	cl->mei_flow_ctrl_creds = 0;
 	cl->timer_count = 0;
 
@@ -1770,44 +1800,3 @@ void mei_cl_all_disconnect(struct mei_device *dev)
 	list_for_each_entry(cl, &dev->file_list, link)
 		mei_cl_set_disconnected(cl);
 }
-
-
-/**
- * mei_cl_all_wakeup  - wake up all readers and writers they can be interrupted
- *
- * @dev: mei device
- */
-void mei_cl_all_wakeup(struct mei_device *dev)
-{
-	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);
-		}
-		if (waitqueue_active(&cl->tx_wait)) {
-			cl_dbg(dev, cl, "Waking up writing client!\n");
-			wake_up_interruptible(&cl->tx_wait);
-		}
-
-		/* synchronized under device mutex */
-		if (waitqueue_active(&cl->ev_wait)) {
-			cl_dbg(dev, cl, "Waking up waiting for event clients!\n");
-			wake_up_interruptible(&cl->ev_wait);
-		}
-	}
-}
-
-/**
- * mei_cl_all_write_clear - clear all pending writes
- *
- * @dev: mei device
- */
-void mei_cl_all_write_clear(struct mei_device *dev)
-{
-	mei_io_list_free(&dev->write_list, NULL);
-	mei_io_list_free(&dev->write_waiting_list, NULL);
-}
-
-
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index fdc43279368f..9925cf1a91ef 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -238,8 +238,6 @@ int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev);
 void mei_cl_notify(struct mei_cl *cl);
 
 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, mei_cl_me_id(cl)
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index a1d978a82806..cfcb46da13f1 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -148,13 +148,8 @@ int mei_reset(struct mei_device *dev)
 	    state != MEI_DEV_POWER_UP) {
 
 		/* remove all waiting requests */
-		mei_cl_all_write_clear(dev);
-
 		mei_cl_all_disconnect(dev);
 
-		/* wake up all readers and writers so they can be interrupted */
-		mei_cl_all_wakeup(dev);
-
 		/* remove entry if already in list */
 		dev_dbg(dev->dev, "remove iamthif from the file list.\n");
 		mei_cl_unlink(&dev->iamthif_cl);
-- 
2.4.3

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

* [char-misc-next 20/27] mei: discard replies from unconnected fixed address clients
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (18 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 19/27] mei: clean write queues and wake waiters on disconnect Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 21/27] mei: fill file pointer in read cb for fixed address client Tomas Winkler
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

A fixed address client in the FW doesn't have a notion of connection and
can send message after the file associated with it was already closed.
Silently discard such messages.
Add inline helpers to detect whether a message is hbm or intended for
a fixed address client

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/interrupt.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 72806ef6efdd..06b744a503a3 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -239,6 +239,16 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
 	return 0;
 }
 
+static inline bool hdr_is_hbm(struct mei_msg_hdr *mei_hdr)
+{
+	return mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0;
+}
+
+static inline bool hdr_is_fixed(struct mei_msg_hdr *mei_hdr)
+{
+	return mei_hdr->host_addr == 0 && mei_hdr->me_addr != 0;
+}
+
 /**
  * mei_irq_read_handler - bottom half read routine after ISR to
  * handle the read processing.
@@ -280,7 +290,7 @@ int mei_irq_read_handler(struct mei_device *dev,
 	}
 
 	/*  HBM message */
-	if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) {
+	if (hdr_is_hbm(mei_hdr)) {
 		ret = mei_hbm_dispatch(dev, mei_hdr);
 		if (ret) {
 			dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n",
@@ -300,6 +310,14 @@ int mei_irq_read_handler(struct mei_device *dev,
 
 	/* if no recipient cl was found we assume corrupted header */
 	if (&cl->link == &dev->file_list) {
+		/* A message for not connected fixed address clients
+		 * should be silently discarded
+		 */
+		if (hdr_is_fixed(mei_hdr)) {
+			mei_irq_discard_msg(dev, mei_hdr);
+			ret = 0;
+			goto reset_slots;
+		}
 		dev_err(dev->dev, "no destination client found 0x%08X\n",
 				dev->rd_msg_hdr);
 		ret = -EBADMSG;
-- 
2.4.3

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

* [char-misc-next 21/27] mei: fill file pointer in read cb for fixed address client
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (19 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 20/27] mei: discard replies from unconnected fixed address clients Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 22/27] mei: fixed address clients for the new platforms Tomas Winkler
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

The read callback created from a flow control request for
a fixed address client have NULL in the file pointer.
Fill the file pointer using a data from a write callback.

This allows us to drop workaround introduced in:
commit eeabfcf5a92a ("mei: connection to fixed address clients from user-space")

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/client.c |  11 +-
 drivers/misc/mei/main.c   |   5 -
 drivers/misc/mei/wd.c     | 391 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 397 insertions(+), 10 deletions(-)
 create mode 100644 drivers/misc/mei/wd.c

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 3a9c656f1425..a27ae2deecb4 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1173,11 +1173,12 @@ err:
 /**
  * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
  *
- * @cl: private data of the file object
+ * @cl: host client
+ * @fp: the file pointer associated with the pointer
  *
  * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
  */
-static int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
+static int mei_cl_flow_ctrl_creds(struct mei_cl *cl, const struct file *fp)
 {
 	int rets;
 
@@ -1188,7 +1189,7 @@ static int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 		return 1;
 
 	if (mei_cl_is_fixed_address(cl)) {
-		rets = mei_cl_read_start(cl, mei_cl_mtu(cl), NULL);
+		rets = mei_cl_read_start(cl, mei_cl_mtu(cl), fp);
 		if (rets && rets != -EBUSY)
 			return rets;
 		return 1;
@@ -1568,7 +1569,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 
 	first_chunk = cb->buf_idx == 0;
 
-	rets = first_chunk ? mei_cl_flow_ctrl_creds(cl) : 1;
+	rets = first_chunk ? mei_cl_flow_ctrl_creds(cl, cb->fp) : 1;
 	if (rets < 0)
 		return rets;
 
@@ -1674,7 +1675,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 	mei_hdr.msg_complete = 0;
 	mei_hdr.internal = cb->internal;
 
-	rets = mei_cl_flow_ctrl_creds(cl);
+	rets = mei_cl_flow_ctrl_creds(cl, cb->fp);
 	if (rets < 0)
 		goto err;
 
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index ba9790ead256..c8a8d4df84e4 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -209,11 +209,6 @@ 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;
 	}
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
new file mode 100644
index 000000000000..7d9b4ee42f65
--- /dev/null
+++ b/drivers/misc/mei/wd.c
@@ -0,0 +1,391 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/watchdog.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hbm.h"
+#include "client.h"
+
+static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
+static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
+
+/*
+ * AMT Watchdog Device
+ */
+#define INTEL_AMT_WATCHDOG_ID "INTCAMT"
+
+/* UUIDs for AMT F/W clients */
+const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
+						0x9D, 0xA9, 0x15, 0x14, 0xCB,
+						0x32, 0xAB);
+
+static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
+{
+	dev_dbg(dev->dev, "wd: set timeout=%d.\n", timeout);
+	memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
+	memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
+}
+
+/**
+ * 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, struct mei_me_client *me_cl)
+{
+	struct mei_cl *cl = &dev->wd_cl;
+	int ret;
+
+	mei_cl_init(cl, dev);
+
+	dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
+	dev->wd_state = MEI_WD_IDLE;
+
+	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, me_cl, NULL);
+	if (ret) {
+		dev_err(dev->dev, "wd: failed to connect = %d\n", ret);
+		mei_cl_unlink(cl);
+		return ret;
+	}
+
+	ret = mei_watchdog_register(dev);
+	if (ret) {
+		mei_cl_disconnect(cl);
+		mei_cl_unlink(cl);
+	}
+	return ret;
+}
+
+/**
+ * mei_wd_send - sends watch dog message to fw.
+ *
+ * @dev: the device structure
+ *
+ * Return: 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 = cl->host_client_id;
+	hdr.me_addr = mei_cl_me_id(cl);
+	hdr.msg_complete = 1;
+	hdr.reserved = 0;
+	hdr.internal = 0;
+
+	if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
+		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 {
+		dev_err(dev->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->dev, "wd: write message failed\n");
+		return ret;
+	}
+
+	ret = mei_cl_flow_ctrl_reduce(cl);
+	if (ret) {
+		dev_err(dev->dev, "wd: flow_ctrl_reduce failed.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * mei_wd_stop - sends watchdog stop message to fw.
+ *
+ * @dev: the device structure
+ *
+ * Return: 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)
+{
+	struct mei_cl *cl = &dev->wd_cl;
+	int ret;
+
+	if (!mei_cl_is_connected(cl) ||
+	    dev->wd_state != MEI_WD_RUNNING)
+		return 0;
+
+	memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
+
+	dev->wd_state = MEI_WD_STOPPING;
+
+	ret = mei_cl_flow_ctrl_creds(cl, NULL);
+	if (ret < 0)
+		goto err;
+
+	if (ret && mei_hbuf_acquire(dev)) {
+		ret = mei_wd_send(dev);
+		if (ret)
+			goto err;
+		dev->wd_pending = false;
+	} else {
+		dev->wd_pending = true;
+	}
+
+	mutex_unlock(&dev->device_lock);
+
+	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) {
+		/* timeout */
+		ret = -ETIME;
+		dev_warn(dev->dev, "wd: stop failed to complete ret=%d\n", ret);
+		goto err;
+	}
+	dev_dbg(dev->dev, "wd: stop completed after %u msec\n",
+			MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
+	return 0;
+err:
+	return ret;
+}
+
+/**
+ * mei_wd_ops_start - wd start command from the watchdog core.
+ *
+ * @wd_dev: watchdog device struct
+ *
+ * Return: 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_start(struct watchdog_device *wd_dev)
+{
+	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) {
+		dev_dbg(dev->dev, "wd: dev_state != MEI_DEV_ENABLED  dev_state = %s\n",
+			mei_dev_state_str(dev->dev_state));
+		goto end_unlock;
+	}
+
+	if (!mei_cl_is_connected(cl)) {
+		cl_dbg(dev, cl, "MEI Driver is not connected to Watchdog Client\n");
+		goto end_unlock;
+	}
+
+	mei_wd_set_start_timeout(dev, dev->wd_timeout);
+
+	err = 0;
+end_unlock:
+	mutex_unlock(&dev->device_lock);
+	return err;
+}
+
+/**
+ * mei_wd_ops_stop -  wd stop command from the watchdog core.
+ *
+ * @wd_dev: watchdog device struct
+ *
+ * Return: 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
+{
+	struct mei_device *dev;
+
+	dev = watchdog_get_drvdata(wd_dev);
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->device_lock);
+	mei_wd_stop(dev);
+	mutex_unlock(&dev->device_lock);
+
+	return 0;
+}
+
+/**
+ * mei_wd_ops_ping - wd ping command from the watchdog core.
+ *
+ * @wd_dev: watchdog device struct
+ *
+ * Return: 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
+{
+	struct mei_device *dev;
+	struct mei_cl *cl;
+	int ret;
+
+	dev = watchdog_get_drvdata(wd_dev);
+	if (!dev)
+		return -ENODEV;
+
+	cl = &dev->wd_cl;
+
+	mutex_lock(&dev->device_lock);
+
+	if (!mei_cl_is_connected(cl)) {
+		cl_err(dev, cl, "wd: not connected.\n");
+		ret = -ENODEV;
+		goto end;
+	}
+
+	dev->wd_state = MEI_WD_RUNNING;
+
+	ret = mei_cl_flow_ctrl_creds(cl, NULL);
+	if (ret < 0)
+		goto end;
+
+	/* Check if we can send the ping to HW*/
+	if (ret && mei_hbuf_acquire(dev)) {
+		dev_dbg(dev->dev, "wd: sending ping\n");
+
+		ret = mei_wd_send(dev);
+		if (ret)
+			goto end;
+		dev->wd_pending = false;
+	} else {
+		dev->wd_pending = true;
+	}
+
+end:
+	mutex_unlock(&dev->device_lock);
+	return ret;
+}
+
+/**
+ * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
+ *
+ * @wd_dev: watchdog device struct
+ * @timeout: timeout value to set
+ *
+ * Return: 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
+		unsigned int timeout)
+{
+	struct mei_device *dev;
+
+	dev = watchdog_get_drvdata(wd_dev);
+	if (!dev)
+		return -ENODEV;
+
+	/* Check Timeout value */
+	if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT)
+		return -EINVAL;
+
+	mutex_lock(&dev->device_lock);
+
+	dev->wd_timeout = timeout;
+	wd_dev->timeout = timeout;
+	mei_wd_set_start_timeout(dev, dev->wd_timeout);
+
+	mutex_unlock(&dev->device_lock);
+
+	return 0;
+}
+
+/*
+ * Watchdog Device structs
+ */
+static const struct watchdog_ops wd_ops = {
+		.owner = THIS_MODULE,
+		.start = mei_wd_ops_start,
+		.stop = mei_wd_ops_stop,
+		.ping = mei_wd_ops_ping,
+		.set_timeout = mei_wd_ops_set_timeout,
+};
+static const struct watchdog_info wd_info = {
+		.identity = INTEL_AMT_WATCHDOG_ID,
+		.options = WDIOF_KEEPALIVEPING |
+			   WDIOF_SETTIMEOUT |
+			   WDIOF_ALARMONLY,
+};
+
+static struct watchdog_device amt_wd_dev = {
+		.info = &wd_info,
+		.ops = &wd_ops,
+		.timeout = MEI_WD_DEFAULT_TIMEOUT,
+		.min_timeout = MEI_WD_MIN_TIMEOUT,
+		.max_timeout = MEI_WD_MAX_TIMEOUT,
+};
+
+
+int mei_watchdog_register(struct mei_device *dev)
+{
+
+	int ret;
+
+	amt_wd_dev.parent = dev->dev;
+	/* 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->dev, "wd: unable to register watchdog device = %d.\n",
+			ret);
+		return ret;
+	}
+
+	dev_dbg(dev->dev, "wd: successfully register watchdog interface.\n");
+	watchdog_set_drvdata(&amt_wd_dev, dev);
+	return 0;
+}
+
+void mei_watchdog_unregister(struct mei_device *dev)
+{
+	if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
+		return;
+
+	watchdog_set_drvdata(&amt_wd_dev, NULL);
+	watchdog_unregister_device(&amt_wd_dev);
+}
+
-- 
2.4.3

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

* [char-misc-next 22/27] mei: fixed address clients for the new platforms
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (20 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 21/27] mei: fill file pointer in read cb for fixed address client Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 23/27] mei: hbm: warn about fw-initiated disconnect Tomas Winkler
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

Enable by default connection to fixed address clients
from user-space for skylake and newer platform.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/debugfs.c | 31 +++++++++++++++++++++++++++++--
 drivers/misc/mei/hbm.c     |  4 ++++
 drivers/misc/mei/hw.h      |  6 ++++++
 drivers/misc/mei/main.c    | 18 ++++++++++++++----
 drivers/misc/mei/mei_dev.h |  4 ++++
 5 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index 6bdd75424fe8..8ad406315741 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -176,6 +176,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
 				 dev->hbm_f_dot_supported);
 		pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n",
 				 dev->hbm_f_ev_supported);
+		pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n",
+				 dev->hbm_f_fa_supported);
 	}
 
 	pos += scnprintf(buf + pos, bufsz - pos, "pg:  %s, %s\n",
@@ -191,6 +193,30 @@ static const struct file_operations mei_dbgfs_fops_devstate = {
 	.llseek = generic_file_llseek,
 };
 
+static ssize_t mei_dbgfs_write_allow_fa(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct mei_device *dev;
+	int ret;
+
+	dev = container_of(file->private_data,
+			   struct mei_device, allow_fixed_address);
+
+	ret = debugfs_write_file_bool(file, user_buf, count, ppos);
+	if (ret < 0)
+		return ret;
+	dev->override_fixed_address = true;
+	return ret;
+}
+
+static const struct file_operations mei_dbgfs_fops_allow_fa = {
+	.open = simple_open,
+	.read = debugfs_read_file_bool,
+	.write = mei_dbgfs_write_allow_fa,
+	.llseek = generic_file_llseek,
+};
+
 /**
  * mei_dbgfs_deregister - Remove the debugfs files and directories
  *
@@ -240,8 +266,9 @@ 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_IRUSR | S_IWUSR, dir,
-				&dev->allow_fixed_address);
+	f = debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir,
+				&dev->allow_fixed_address,
+				&mei_dbgfs_fops_allow_fa);
 	if (!f) {
 		dev_err(dev->dev, "allow_fixed_address: registration failed\n");
 		goto err;
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index e7b7aad0999b..3915b8e8d0f1 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -979,6 +979,10 @@ static void mei_hbm_config_features(struct mei_device *dev)
 	/* Notification Event Support */
 	if (dev->version.major_version >= HBM_MAJOR_VERSION_EV)
 		dev->hbm_f_ev_supported = 1;
+
+	/* Fixed Address Client Support */
+	if (dev->version.major_version >= HBM_MAJOR_VERSION_FA)
+		dev->hbm_f_fa_supported = 1;
 }
 
 /**
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 4c5d6cfd79b4..459ad596df66 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -64,6 +64,12 @@
 #define HBM_MINOR_VERSION_EV               0
 #define HBM_MAJOR_VERSION_EV               2
 
+/*
+ * MEI version with fixed address client support
+ */
+#define HBM_MINOR_VERSION_FA               0
+#define HBM_MAJOR_VERSION_FA               2
+
 /* Host bus message command opcode */
 #define MEI_HBM_CMD_OP_MSK                  0x7f
 /* Host bus message command RESPONSE */
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index c8a8d4df84e4..3ec6236c8782 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -369,12 +369,22 @@ 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 && !dev->allow_fixed_address)) {
+	if (!me_cl) {
 		dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
 			&data->in_client_uuid);
-		mei_me_cl_put(me_cl);
-		return  -ENOTTY;
+		rets = -ENOTTY;
+		goto end;
+	}
+
+	if (me_cl->props.fixed_address) {
+		bool forbidden = dev->override_fixed_address ?
+			 !dev->allow_fixed_address : !dev->hbm_f_fa_supported;
+		if (forbidden) {
+			dev_dbg(dev->dev, "Connection forbidden to FW Client UUID = %pUl\n",
+				&data->in_client_uuid);
+			rets = -ENOTTY;
+			goto end;
+		}
 	}
 
 	dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 70c4da015401..6d97f3335e22 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -396,6 +396,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @hbm_f_dc_supported  : hbm feature dynamic clients
  * @hbm_f_dot_supported : hbm feature disconnect on timeout
  * @hbm_f_ev_supported  : hbm feature event notification
+ * @hbm_f_fa_supported  : hbm feature fixed address client
  *
  * @me_clients_rwsem: rw lock over me_clients list
  * @me_clients  : list of FW clients
@@ -404,6 +405,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @me_client_index : last FW client index in enumeration
  *
  * @allow_fixed_address: allow user space to connect a fixed client
+ * @override_fixed_address: force allow fixed address behavior
  *
  * @amthif_cmd_list : amthif list for cmd waiting
  * @iamthif_fp : file for current amthif operation
@@ -483,6 +485,7 @@ struct mei_device {
 	unsigned int hbm_f_dc_supported:1;
 	unsigned int hbm_f_dot_supported:1;
 	unsigned int hbm_f_ev_supported:1;
+	unsigned int hbm_f_fa_supported:1;
 
 	struct rw_semaphore me_clients_rwsem;
 	struct list_head me_clients;
@@ -491,6 +494,7 @@ struct mei_device {
 	unsigned long me_client_index;
 
 	bool allow_fixed_address;
+	bool override_fixed_address;
 
 	/* amthif list for cmd waiting */
 	struct mei_cl_cb amthif_cmd_list;
-- 
2.4.3

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

* [char-misc-next 23/27] mei: hbm: warn about fw-initiated disconnect
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (21 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 22/27] mei: fixed address clients for the new platforms Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 24/27] mei: drop reserved host client ids Tomas Winkler
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

The FW can initiate client disconnection only because an error
condition, hence it make sense to bump the debug message to the warning
level to have an entery in the log.

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

diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 9925cf1a91ef..be6929620d61 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -245,6 +245,9 @@ void mei_cl_all_disconnect(struct mei_device *dev);
 #define cl_dbg(dev, cl, format, arg...) \
 	dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
 
+#define cl_warn(dev, cl, format, arg...) \
+	dev_warn((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
+
 #define cl_err(dev, cl, format, arg...) \
 	dev_err((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
 
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 3915b8e8d0f1..a2f32b0eb649 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -866,7 +866,7 @@ 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, "fw disconnect request received\n");
+		cl_warn(dev, cl, "fw disconnect request received\n");
 		cl->state = MEI_FILE_DISCONNECTING;
 		cl->timer_count = 0;
 
-- 
2.4.3

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

* [char-misc-next 24/27] mei: drop reserved host client ids
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (22 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 23/27] mei: hbm: warn about fw-initiated disconnect Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 25/27] mei: bus: run rescan on me_clients list change Tomas Winkler
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

The reserved host clients can be obsoleted now, a portion of the
platforms is shipped without iAMT enabled, where the reservation is not
relevant and for platforms with iAMT dynamic allocation is sufficient.
Dropping reserved ids makes enumeration more flexible and generic

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c    |  2 +-
 drivers/misc/mei/bus-fixup.c |  2 +-
 drivers/misc/mei/bus.c       |  2 +-
 drivers/misc/mei/client.c    | 15 +++++----------
 drivers/misc/mei/client.h    |  4 ++--
 drivers/misc/mei/main.c      |  2 +-
 drivers/misc/mei/mei_dev.h   |  8 --------
 7 files changed, 11 insertions(+), 24 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index ca2efc3602df..de194ef573ee 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -71,7 +71,7 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 
 	mei_cl_init(cl, dev);
 
-	ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
+	ret = mei_cl_link(cl);
 	if (ret < 0) {
 		dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
 		return ret;
diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c
index b87323f4bb14..e9e6ea3ab73c 100644
--- a/drivers/misc/mei/bus-fixup.c
+++ b/drivers/misc/mei/bus-fixup.c
@@ -239,7 +239,7 @@ static void mei_nfc(struct mei_cl_device *cldev)
 
 	mutex_lock(&bus->device_lock);
 	/* we need to connect to INFO GUID */
-	cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY);
+	cl = mei_cl_alloc_linked(bus);
 	if (IS_ERR(cl)) {
 		ret = PTR_ERR(cl);
 		cl = NULL;
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 83b084558ee5..bc18e5519da6 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -417,7 +417,7 @@ int mei_cldev_enable(struct mei_cl_device *cldev)
 
 	if (!cl) {
 		mutex_lock(&bus->device_lock);
-		cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY);
+		cl = mei_cl_alloc_linked(bus);
 		mutex_unlock(&bus->device_lock);
 		if (IS_ERR(cl))
 			return PTR_ERR(cl);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index a27ae2deecb4..2890669b81f9 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -587,27 +587,23 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
  * mei_cl_link - allocate host id in the host map
  *
  * @cl: host client
- * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
  *
  * Return: 0 on success
  *	-EINVAL on incorrect values
  *	-EMFILE if open count exceeded.
  */
-int mei_cl_link(struct mei_cl *cl, int id)
+int mei_cl_link(struct mei_cl *cl)
 {
 	struct mei_device *dev;
 	long open_handle_count;
+	int id;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -EINVAL;
 
 	dev = cl->dev;
 
-	/* If Id is not assigned get one*/
-	if (id == MEI_HOST_CLIENT_ID_ANY)
-		id = find_first_zero_bit(dev->host_clients_map,
-					MEI_CLIENTS_MAX);
-
+	id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
 	if (id >= MEI_CLIENTS_MAX) {
 		dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
 		return -EMFILE;
@@ -1143,11 +1139,10 @@ nortpm:
  * mei_cl_alloc_linked - allocate and link host client
  *
  * @dev: the device structure
- * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
  *
  * Return: cl on success ERR_PTR on failure
  */
-struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id)
+struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev)
 {
 	struct mei_cl *cl;
 	int ret;
@@ -1158,7 +1153,7 @@ struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id)
 		goto err;
 	}
 
-	ret = mei_cl_link(cl, id);
+	ret = mei_cl_link(cl);
 	if (ret)
 		goto err;
 
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index be6929620d61..a912ea686d97 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -107,10 +107,10 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev);
 void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
 
 
-int mei_cl_link(struct mei_cl *cl, int id);
+int mei_cl_link(struct mei_cl *cl);
 int mei_cl_unlink(struct mei_cl *cl);
 
-struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id);
+struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev);
 
 struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl,
 				 const struct file *fp);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 3ec6236c8782..527ad1ff145c 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -65,7 +65,7 @@ static int mei_open(struct inode *inode, struct file *file)
 		goto err_unlock;
 	}
 
-	cl = mei_cl_alloc_linked(dev, MEI_HOST_CLIENT_ID_ANY);
+	cl = mei_cl_alloc_linked(dev);
 	if (IS_ERR(cl)) {
 		err = PTR_ERR(cl);
 		goto err_unlock;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 6d97f3335e22..320ddae5ee1e 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -53,14 +53,6 @@ extern const uuid_le mei_amthif_guid;
  */
 #define  MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1)
 
-/*
- * Internal Clients Number
- */
-#define MEI_HOST_CLIENT_ID_ANY        (-1)
-#define MEI_HBM_HOST_CLIENT_ID         0 /* not used, just for documentation */
-#define MEI_IAMTHIF_HOST_CLIENT_ID     2
-
-
 /* File state */
 enum file_state {
 	MEI_FILE_INITIALIZING = 0,
-- 
2.4.3

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

* [char-misc-next 25/27] mei: bus: run rescan on me_clients list change
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (23 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 24/27] mei: drop reserved host client ids Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 26/27] mei: hbm: send immediate reply flag in enum request Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 27/27] mei: split amthif client init from end of clients enumeration Tomas Winkler
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

Since clients can be now added and removed during runtime
we need to run bus rescan whenever me_clients list is modified.

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

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index bc18e5519da6..951d32265040 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -977,6 +977,14 @@ void mei_cl_bus_rescan(struct mei_device *bus)
 	dev_dbg(bus->dev, "rescan end");
 }
 
+void mei_cl_bus_rescan_work(struct work_struct *work)
+{
+	struct mei_device *bus =
+		container_of(work, struct mei_device, bus_rescan_work);
+
+	mei_cl_bus_rescan(bus);
+}
+
 int __mei_cldev_driver_register(struct mei_cl_driver *cldrv,
 				struct module *owner)
 {
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index a2f32b0eb649..0c9310ad6136 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -401,6 +401,9 @@ static int mei_hbm_fw_add_cl_req(struct mei_device *dev,
 	if (ret)
 		status = !MEI_HBMS_SUCCESS;
 
+	if (dev->dev_state == MEI_DEV_ENABLED)
+		schedule_work(&dev->bus_rescan_work);
+
 	return mei_hbm_add_cl_resp(dev, req->me_addr, status);
 }
 
@@ -789,8 +792,11 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,
 		cl->state = MEI_FILE_CONNECTED;
 	else {
 		cl->state = MEI_FILE_DISCONNECT_REPLY;
-		if (rs->status == MEI_CL_CONN_NOT_FOUND)
+		if (rs->status == MEI_CL_CONN_NOT_FOUND) {
 			mei_me_cl_del(dev, cl->me_cl);
+			if (dev->dev_state == MEI_DEV_ENABLED)
+				schedule_work(&dev->bus_rescan_work);
+		}
 	}
 	cl->status = mei_cl_conn_status_to_errno(rs->status);
 }
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index cfcb46da13f1..52fde2b498ef 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -93,6 +93,7 @@ void mei_cancel_work(struct mei_device *dev)
 {
 	cancel_work_sync(&dev->init_work);
 	cancel_work_sync(&dev->reset_work);
+	cancel_work_sync(&dev->bus_rescan_work);
 
 	cancel_delayed_work(&dev->timer_work);
 }
@@ -394,6 +395,7 @@ void mei_device_init(struct mei_device *dev,
 	INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
 	INIT_WORK(&dev->init_work, mei_host_client_init);
 	INIT_WORK(&dev->reset_work, mei_reset_work);
+	INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work);
 
 	INIT_LIST_HEAD(&dev->iamthif_cl.link);
 	mei_io_list_init(&dev->amthif_cmd_list);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 320ddae5ee1e..c31adb8a0cff 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -304,6 +304,7 @@ struct mei_hw_ops {
 
 /* MEI bus API*/
 void mei_cl_bus_rescan(struct mei_device *bus);
+void mei_cl_bus_rescan_work(struct work_struct *work);
 void mei_cl_bus_dev_fixup(struct mei_cl_device *dev);
 ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 			bool blocking);
@@ -410,6 +411,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  *
  * @init_work   : work item for the device init
  * @reset_work  : work item for the device reset
+ * @bus_rescan_work : work item for the bus rescan
  *
  * @device_list : mei client bus list
  * @cl_bus_lock : client bus list lock
@@ -501,6 +503,7 @@ struct mei_device {
 
 	struct work_struct init_work;
 	struct work_struct reset_work;
+	struct work_struct bus_rescan_work;
 
 	/* List of bus devices */
 	struct list_head device_list;
-- 
2.4.3

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

* [char-misc-next 26/27] mei: hbm: send immediate reply flag in enum request
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (24 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 25/27] mei: bus: run rescan on me_clients list change Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  2016-02-07 21:35 ` [char-misc-next 27/27] mei: split amthif client init from end of clients enumeration Tomas Winkler
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

Signal the FW that it can send an HBM enumeration answer immediately,
without waiting for FW initialization completion, meaning before
all the FW clients are ready and registered.

Organize enumeration response options to enum as a byproduct.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/debugfs.c |  2 ++
 drivers/misc/mei/hbm.c     |  8 +++++++-
 drivers/misc/mei/hw.h      | 25 +++++++++++++++++++++----
 drivers/misc/mei/mei_dev.h |  2 ++
 4 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index 8ad406315741..c6c051b52f55 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -172,6 +172,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
 				 dev->hbm_f_pg_supported);
 		pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
 				 dev->hbm_f_dc_supported);
+		pos += scnprintf(buf + pos, bufsz - pos, "\tIE: %01d\n",
+				 dev->hbm_f_ie_supported);
 		pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",
 				 dev->hbm_f_dot_supported);
 		pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n",
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 0c9310ad6136..d2798d5b0a9d 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -301,7 +301,10 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev)
 	enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
 	memset(enum_req, 0, len);
 	enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
-	enum_req->allow_add = dev->hbm_f_dc_supported;
+	enum_req->flags |= dev->hbm_f_dc_supported ?
+			   MEI_HBM_ENUM_F_ALLOW_ADD : 0;
+	enum_req->flags |= dev->hbm_f_ie_supported ?
+			   MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0;
 
 	ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
 	if (ret) {
@@ -978,6 +981,9 @@ static void mei_hbm_config_features(struct mei_device *dev)
 	if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
 		dev->hbm_f_dc_supported = 1;
 
+	if (dev->version.major_version >= HBM_MAJOR_VERSION_IE)
+		dev->hbm_f_ie_supported = 1;
+
 	/* disconnect on connect timeout instead of link reset */
 	if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
 		dev->hbm_f_dot_supported = 1;
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 459ad596df66..9daf3f9aed25 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -53,6 +53,12 @@
 #define HBM_MAJOR_VERSION_DC               2
 
 /*
+ * MEI version with immediate reply to enum request support
+ */
+#define HBM_MINOR_VERSION_IE               0
+#define HBM_MAJOR_VERSION_IE               2
+
+/*
  * MEI version with disconnect on connection timeout support
  */
 #define HBM_MINOR_VERSION_DOT              0
@@ -246,15 +252,26 @@ struct hbm_me_stop_request {
 } __packed;
 
 /**
- * struct hbm_host_enum_request -  enumeration request from host to fw
+ * enum hbm_host_enum_flags - enumeration request flags (HBM version >= 2.0)
  *
- * @hbm_cmd: bus message command header
- * @allow_add: allow dynamic clients add HBM version >= 2.0
+ * @MEI_HBM_ENUM_F_ALLOW_ADD: allow dynamic clients add
+ * @MEI_HBM_ENUM_F_IMMEDIATE_ENUM: allow FW to send answer immediately
+ */
+enum hbm_host_enum_flags {
+	MEI_HBM_ENUM_F_ALLOW_ADD = BIT(0),
+	MEI_HBM_ENUM_F_IMMEDIATE_ENUM = BIT(1),
+};
+
+/**
+ * struct hbm_host_enum_request - enumeration request from host to fw
+ *
+ * @hbm_cmd : bus message command header
+ * @flags   : request flags
  * @reserved: reserved
  */
 struct hbm_host_enum_request {
 	u8 hbm_cmd;
-	u8 allow_add;
+	u8 flags;
 	u8 reserved[2];
 } __packed;
 
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index c31adb8a0cff..2b9160e506d7 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -390,6 +390,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @hbm_f_dot_supported : hbm feature disconnect on timeout
  * @hbm_f_ev_supported  : hbm feature event notification
  * @hbm_f_fa_supported  : hbm feature fixed address client
+ * @hbm_f_ie_supported  : hbm feature immediate reply to enum request
  *
  * @me_clients_rwsem: rw lock over me_clients list
  * @me_clients  : list of FW clients
@@ -480,6 +481,7 @@ struct mei_device {
 	unsigned int hbm_f_dot_supported:1;
 	unsigned int hbm_f_ev_supported:1;
 	unsigned int hbm_f_fa_supported:1;
+	unsigned int hbm_f_ie_supported:1;
 
 	struct rw_semaphore me_clients_rwsem;
 	struct list_head me_clients;
-- 
2.4.3

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

* [char-misc-next 27/27] mei: split amthif client init from end of clients enumeration
  2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
                   ` (25 preceding siblings ...)
  2016-02-07 21:35 ` [char-misc-next 26/27] mei: hbm: send immediate reply flag in enum request Tomas Winkler
@ 2016-02-07 21:35 ` Tomas Winkler
  26 siblings, 0 replies; 28+ messages in thread
From: Tomas Winkler @ 2016-02-07 21:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

The amthif FW client can appear after the end of client enumeration.
Amthif host client initialization is done now at FW client discovery
time.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c  |  5 +++--
 drivers/misc/mei/bus.c     |  8 ++++++++
 drivers/misc/mei/client.c  | 17 ++---------------
 drivers/misc/mei/client.h  |  2 +-
 drivers/misc/mei/hbm.c     |  2 +-
 drivers/misc/mei/init.c    |  2 --
 drivers/misc/mei/mei_dev.h |  2 --
 7 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index de194ef573ee..04525ada9eda 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -67,6 +67,9 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 	struct mei_cl *cl = &dev->iamthif_cl;
 	int ret;
 
+	if (mei_cl_is_connected(cl))
+		return 0;
+
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
 
 	mei_cl_init(cl, dev);
@@ -79,8 +82,6 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 
 	ret = mei_cl_connect(cl, me_cl, NULL);
 
-	dev->iamthif_state = MEI_IAMTHIF_IDLE;
-
 	return ret;
 }
 
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 951d32265040..f4cf43b47c7a 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -981,6 +981,14 @@ void mei_cl_bus_rescan_work(struct work_struct *work)
 {
 	struct mei_device *bus =
 		container_of(work, struct mei_device, bus_rescan_work);
+	struct mei_me_client *me_cl;
+
+	mutex_lock(&bus->device_lock);
+	me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid);
+	if (me_cl)
+		mei_amthif_host_init(bus, me_cl);
+	mei_me_cl_put(me_cl);
+	mutex_unlock(&bus->device_lock);
 
 	mei_cl_bus_rescan(bus);
 }
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 2890669b81f9..af6816bc268f 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -666,25 +666,12 @@ int mei_cl_unlink(struct mei_cl *cl)
 	return 0;
 }
 
-
-void mei_host_client_init(struct work_struct *work)
+void mei_host_client_init(struct mei_device *dev)
 {
-	struct mei_device *dev =
-		container_of(work, struct mei_device, init_work);
-	struct mei_me_client *me_cl;
-
-	mutex_lock(&dev->device_lock);
-
-	me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
-	if (me_cl)
-		mei_amthif_host_init(dev, me_cl);
-	mei_me_cl_put(me_cl);
-
 	dev->dev_state = MEI_DEV_ENABLED;
 	dev->reset_count = 0;
-	mutex_unlock(&dev->device_lock);
 
-	mei_cl_bus_rescan(dev);
+	schedule_work(&dev->bus_rescan_work);
 
 	pm_runtime_mark_last_busy(dev->dev);
 	dev_dbg(dev->dev, "rpm: autosuspend\n");
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index a912ea686d97..0d7a3a1fef78 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -226,7 +226,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 
 void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
 
-void mei_host_client_init(struct work_struct *work);
+void mei_host_client_init(struct mei_device *dev);
 
 u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop);
 enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index d2798d5b0a9d..5e305d2605f3 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -549,7 +549,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
 	/* We got all client properties */
 	if (next_client_index == MEI_CLIENTS_MAX) {
 		dev->hbm_state = MEI_HBM_STARTED;
-		schedule_work(&dev->init_work);
+		mei_host_client_init(dev);
 
 		return 0;
 	}
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 52fde2b498ef..f7c8dfdb6a12 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -91,7 +91,6 @@ EXPORT_SYMBOL_GPL(mei_fw_status2str);
  */
 void mei_cancel_work(struct mei_device *dev)
 {
-	cancel_work_sync(&dev->init_work);
 	cancel_work_sync(&dev->reset_work);
 	cancel_work_sync(&dev->bus_rescan_work);
 
@@ -393,7 +392,6 @@ void mei_device_init(struct mei_device *dev,
 	mei_io_list_init(&dev->ctrl_rd_list);
 
 	INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
-	INIT_WORK(&dev->init_work, mei_host_client_init);
 	INIT_WORK(&dev->reset_work, mei_reset_work);
 	INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work);
 
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 2b9160e506d7..db78e6d99456 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -410,7 +410,6 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @iamthif_state : amthif processor state
  * @iamthif_canceled : current amthif command is canceled
  *
- * @init_work   : work item for the device init
  * @reset_work  : work item for the device reset
  * @bus_rescan_work : work item for the bus rescan
  *
@@ -503,7 +502,6 @@ struct mei_device {
 	enum iamthif_states iamthif_state;
 	bool iamthif_canceled;
 
-	struct work_struct init_work;
 	struct work_struct reset_work;
 	struct work_struct bus_rescan_work;
 
-- 
2.4.3

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

end of thread, other threads:[~2016-02-07 21:44 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-07 21:35 [char-misc-next 00/27] mei: fixes, improvements, and cleanups Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 01/27] mei: debugfs: adjust active clients print buffer Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 02/27] mei: debugfs: allow hbm features list dump in earlier stages Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 03/27] mei: fix possible integer overflow issue Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 04/27] mei: call stop on failed char device register Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 05/27] mei: amthif: don't copy from an empty buffer Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 06/27] mei: amthif: don't drop read packets on timeout Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 07/27] mei: constify struct file pointer Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 08/27] mei: rename variable names 'file_object' to fp Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 09/27] mei: amthif: allow only one request at a time Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 10/27] mei: amthif: replace amthif_rd_complete_list with rd_completed Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 11/27] mei: amthif: drop parameter validation from mei_amthif_write Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 12/27] mei: amthif: use rx_wait queue also for amthif client Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 13/27] mei: amthif: interrupt reader on link reset Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 14/27] mei: bus: fix RX event scheduling Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 15/27] mei: bus: fix notification event delivery Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 16/27] mei: bus: check if the device is enabled before data transfer Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 17/27] mei: drop superfluous closing bracket from write traces Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 18/27] mei: wake blocked write on link reset Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 19/27] mei: clean write queues and wake waiters on disconnect Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 20/27] mei: discard replies from unconnected fixed address clients Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 21/27] mei: fill file pointer in read cb for fixed address client Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 22/27] mei: fixed address clients for the new platforms Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 23/27] mei: hbm: warn about fw-initiated disconnect Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 24/27] mei: drop reserved host client ids Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 25/27] mei: bus: run rescan on me_clients list change Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 26/27] mei: hbm: send immediate reply flag in enum request Tomas Winkler
2016-02-07 21:35 ` [char-misc-next 27/27] mei: split amthif client init from end of clients enumeration Tomas Winkler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).