linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [char-misc-next v2 0/9] mei: rx enhancements
@ 2016-07-25 22:06 Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 1/9] mei: drop redundant krealloc and checks in irq read Tomas Winkler
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

This patch series contains mostly fixes and enhancements
of the rx path:
1. Better handling of fixed address clients
2. Support for consecutive reads
3. Further amthif client diet
V2:
1. Remove patches that were sent twice by mistake
2. Fix one-liner in (mei: add wrapper for queuing control commands)
3. New patch that fixes a deadlock during device reset
  (mei: amthif: fix deadlock in initialization during a reset)

Alexander Usyskin (7):
  mei: drop redundant krealloc and checks in irq read
  mei: prepare read cb for fixed address clients on the receive path
    only.
  mei: rx flow control counter
  mei: enqueue consecutive reads
  mei: amthif: drop mei_amthif_read
  mei: drop unused file transaction states
  mei: amthif: fix deadlock in initialization during a reset

Tomas Winkler (2):
  mei: use consistent naming for TX control flow credits
  mei: add wrapper for queuing control commands.

 drivers/misc/mei/amthif.c    | 120 ++++----------------------------
 drivers/misc/mei/bus.c       |   6 +-
 drivers/misc/mei/client.c    | 161 ++++++++++++++++++++++---------------------
 drivers/misc/mei/client.h    |   5 +-
 drivers/misc/mei/hbm.c       |  45 ++++++------
 drivers/misc/mei/interrupt.c |  39 ++++-------
 drivers/misc/mei/main.c      |  46 ++++++-------
 drivers/misc/mei/mei_dev.h   |  18 ++---
 8 files changed, 163 insertions(+), 277 deletions(-)

-- 
2.7.4

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

* [char-misc-next v2 1/9] mei: drop redundant krealloc and checks in irq read
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 2/9] mei: prepare read cb for fixed address clients on the receive path only Tomas Winkler
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

The read callback is always prepared with MTU-sized buffer and the FW
can't send more than the MTU in one message.
Checking for buffer existence and krealloc to increase receive buffer
size are redundant and may be safely discarded.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: resend
 drivers/misc/mei/interrupt.c | 36 +++++++++++-------------------------
 1 file changed, 11 insertions(+), 25 deletions(-)

diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 44ba90140725..36382d782e20 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -102,18 +102,17 @@ 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) {
 		if (!mei_cl_is_fixed_address(cl)) {
 			cl_err(dev, cl, "pending read cb not found\n");
-			goto out;
+			goto discard;
 		}
 		cb = mei_cl_alloc_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, cl->fp);
 		if (!cb)
-			goto out;
+			goto discard;
 		list_add_tail(&cb->list, &cl->rd_pending);
 	}
 
@@ -121,14 +120,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 		cl_dbg(dev, cl, "not connected\n");
 		list_move_tail(&cb->list, &complete_list->list);
 		cb->status = -ENODEV;
-		goto out;
-	}
-
-	if (cb->buf.size == 0 || cb->buf.data == NULL) {
-		cl_err(dev, cl, "response buffer is not allocated.\n");
-		list_move_tail(&cb->list, &complete_list->list);
-		cb->status = -ENOMEM;
-		goto out;
+		goto discard;
 	}
 
 	buf_sz = mei_hdr->length + cb->buf_idx;
@@ -139,25 +131,19 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 
 		list_move_tail(&cb->list, &complete_list->list);
 		cb->status = -EMSGSIZE;
-		goto out;
+		goto discard;
 	}
 
 	if (cb->buf.size < buf_sz) {
 		cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n",
 			cb->buf.size, mei_hdr->length, cb->buf_idx);
-		buffer = krealloc(cb->buf.data, buf_sz, GFP_KERNEL);
 
-		if (!buffer) {
-			cb->status = -ENOMEM;
-			list_move_tail(&cb->list, &complete_list->list);
-			goto out;
-		}
-		cb->buf.data = buffer;
-		cb->buf.size = buf_sz;
+		list_move_tail(&cb->list, &complete_list->list);
+		cb->status = -EMSGSIZE;
+		goto discard;
 	}
 
-	buffer = cb->buf.data + cb->buf_idx;
-	mei_read_slots(dev, buffer, mei_hdr->length);
+	mei_read_slots(dev, cb->buf.data + cb->buf_idx, mei_hdr->length);
 
 	cb->buf_idx += mei_hdr->length;
 
@@ -169,10 +155,10 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 		pm_request_autosuspend(dev->dev);
 	}
 
-out:
-	if (!buffer)
-		mei_irq_discard_msg(dev, mei_hdr);
+	return 0;
 
+discard:
+	mei_irq_discard_msg(dev, mei_hdr);
 	return 0;
 }
 
-- 
2.7.4

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

* [char-misc-next v2 2/9] mei: prepare read cb for fixed address clients on the receive path only.
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 1/9] mei: drop redundant krealloc and checks in irq read Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 3/9] mei: rx flow control counter Tomas Winkler
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

The read callbacks for the fixed address clients, that don't have flow
control are built now on the receive path. In order to have a single
allocation place we remove the allocation from the read request.

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

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 2a09db86e50e..05cacc3e718f 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1459,17 +1459,15 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
 		return  -ENOTTY;
 	}
 
+	if (mei_cl_is_fixed_address(cl))
+		return 0;
+
 	/* always allocate at least client max message */
 	length = max_t(size_t, length, mei_cl_mtu(cl));
 	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
 	if (!cb)
 		return -ENOMEM;
 
-	if (mei_cl_is_fixed_address(cl)) {
-		list_add_tail(&cb->list, &cl->rd_pending);
-		return 0;
-	}
-
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
 		pm_runtime_put_noidle(dev->dev);
-- 
2.7.4

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

* [char-misc-next v2 3/9] mei: rx flow control counter
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 1/9] mei: drop redundant krealloc and checks in irq read Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 2/9] mei: prepare read cb for fixed address clients on the receive path only Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 4/9] mei: use consistent naming for TX control flow credits Tomas Winkler
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

Use RX flow control counter in the host client structure to
track the number of simultaneous outstanding reads.
This eliminates search in queues and makes ground for
enabling for parallel read.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: resend
 drivers/misc/mei/amthif.c  |  1 +
 drivers/misc/mei/client.c  | 40 +++++++++++++---------------------------
 drivers/misc/mei/mei_dev.h |  4 ++--
 3 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 26568c5beb25..227fd5a816a6 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -202,6 +202,7 @@ static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file)
 		return -ENOMEM;
 
 	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+	cl->rx_flow_ctrl_creds++;
 
 	dev->iamthif_state = MEI_IAMTHIF_READING;
 	cl->fp = cb->fp;
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 05cacc3e718f..ded11de90a26 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -735,6 +735,7 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
 	mei_io_list_flush(&dev->ctrl_wr_list, cl);
 	mei_cl_wake_all(cl);
 	cl->mei_flow_ctrl_creds = 0;
+	cl->rx_flow_ctrl_creds = 0;
 	cl->timer_count = 0;
 
 	if (!cl->me_cl)
@@ -1409,25 +1410,6 @@ out:
 }
 
 /**
- * mei_cl_is_read_fc_cb - check if read cb is waiting for flow control
- *                        for given host client
- *
- * @cl: host client
- *
- * Return: true, if found at least one cb.
- */
-static bool mei_cl_is_read_fc_cb(struct mei_cl *cl)
-{
-	struct mei_device *dev = cl->dev;
-	struct mei_cl_cb *cb;
-
-	list_for_each_entry(cb, &dev->ctrl_wr_list.list, list)
-		if (cb->fop_type == MEI_FOP_READ && cb->cl == cl)
-			return true;
-	return false;
-}
-
-/**
  * mei_cl_read_start - the start read client message function.
  *
  * @cl: host client
@@ -1450,10 +1432,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
 	if (!mei_cl_is_connected(cl))
 		return -ENODEV;
 
-	/* HW currently supports only one pending read */
-	if (!list_empty(&cl->rd_pending) || mei_cl_is_read_fc_cb(cl))
-		return -EBUSY;
-
 	if (!mei_me_cl_is_active(cl->me_cl)) {
 		cl_err(dev, cl, "no such me client\n");
 		return  -ENOTTY;
@@ -1462,12 +1440,18 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
 	if (mei_cl_is_fixed_address(cl))
 		return 0;
 
+	/* HW currently supports only one pending read */
+	if (cl->rx_flow_ctrl_creds)
+		return -EBUSY;
+
 	/* always allocate at least client max message */
 	length = max_t(size_t, length, mei_cl_mtu(cl));
 	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
 	if (!cb)
 		return -ENOMEM;
 
+	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
 		pm_runtime_put_noidle(dev->dev);
@@ -1475,16 +1459,15 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
 		goto nortpm;
 	}
 
+	rets = 0;
 	if (mei_hbuf_acquire(dev)) {
 		rets = mei_hbm_cl_flow_control_req(dev, cl);
 		if (rets < 0)
 			goto out;
 
-		list_add_tail(&cb->list, &cl->rd_pending);
-	} else {
-		rets = 0;
-		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+		list_move_tail(&cb->list, &cl->rd_pending);
 	}
+	cl->rx_flow_ctrl_creds++;
 
 out:
 	cl_dbg(dev, cl, "rpm: autosuspend\n");
@@ -1732,6 +1715,9 @@ 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 (!mei_cl_is_fixed_address(cl) &&
+		    !WARN_ON(!cl->rx_flow_ctrl_creds))
+			cl->rx_flow_ctrl_creds--;
 		if (!mei_cl_bus_rx_event(cl))
 			wake_up_interruptible(&cl->rx_wait);
 		break;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index aaefbc87c2fc..8bdb28054423 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -203,8 +203,8 @@ struct mei_cl_cb {
  * @fp: file associated with client
  * @host_client_id: host id
  * @mei_flow_ctrl_creds: transmit flow credentials
+ * @rx_flow_ctrl_creds: receive flow credentials
  * @timer_count:  watchdog timer for operation completion
- * @reserved: reserved for alignment
  * @notify_en: notification - enabled/disabled
  * @notify_ev: pending notification event
  * @writing_state: state of the tx
@@ -227,8 +227,8 @@ struct mei_cl {
 	const struct file *fp;
 	u8 host_client_id;
 	u8 mei_flow_ctrl_creds;
+	u8 rx_flow_ctrl_creds;
 	u8 timer_count;
-	u8 reserved;
 	u8 notify_en;
 	u8 notify_ev;
 	enum mei_file_transaction_states writing_state;
-- 
2.7.4

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

* [char-misc-next v2 4/9] mei: use consistent naming for TX control flow credits
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
                   ` (2 preceding siblings ...)
  2016-07-25 22:06 ` [char-misc-next v2 3/9] mei: rx flow control counter Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 5/9] mei: add wrapper for queuing control commands Tomas Winkler
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

With the introduction of the receive control flow credits prefixed with
rx_ we add tx_ prefix to the variables and function used for tracking
the transmit control flow credits.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: resend
 drivers/misc/mei/client.c  | 39 +++++++++++++++++++--------------------
 drivers/misc/mei/hbm.c     | 41 ++++++++++++++++++++---------------------
 drivers/misc/mei/mei_dev.h |  8 ++++----
 3 files changed, 43 insertions(+), 45 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index ded11de90a26..89425a8795a8 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -734,8 +734,8 @@ void mei_cl_set_disconnected(struct mei_cl *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->rx_flow_ctrl_creds = 0;
+	cl->tx_flow_ctrl_creds = 0;
 	cl->timer_count = 0;
 
 	if (!cl->me_cl)
@@ -745,7 +745,7 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
 		cl->me_cl->connect_count--;
 
 	if (cl->me_cl->connect_count == 0)
-		cl->me_cl->mei_flow_ctrl_creds = 0;
+		cl->me_cl->tx_flow_ctrl_creds = 0;
 
 	mei_me_cl_put(cl->me_cl);
 	cl->me_cl = NULL;
@@ -1140,43 +1140,42 @@ err:
 	return ERR_PTR(ret);
 }
 
-
-
 /**
- * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
+ * mei_cl_tx_flow_ctrl_creds - checks flow_control credits for cl.
  *
  * @cl: host client
  *
- * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
+ * Return: 1 if tx_flow_ctrl_creds >0, 0 - otherwise.
  */
-static int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
+static int mei_cl_tx_flow_ctrl_creds(struct mei_cl *cl)
 {
 	if (WARN_ON(!cl || !cl->me_cl))
 		return -EINVAL;
 
-	if (cl->mei_flow_ctrl_creds > 0)
+	if (cl->tx_flow_ctrl_creds > 0)
 		return 1;
 
 	if (mei_cl_is_fixed_address(cl))
 		return 1;
 
 	if (mei_cl_is_single_recv_buf(cl)) {
-		if (cl->me_cl->mei_flow_ctrl_creds > 0)
+		if (cl->me_cl->tx_flow_ctrl_creds > 0)
 			return 1;
 	}
 	return 0;
 }
 
 /**
- * mei_cl_flow_ctrl_reduce - reduces flow_control.
+ * mei_cl_tx_flow_ctrl_creds_reduce - reduces transmit flow control credits
+ *   for a client
  *
- * @cl: private data of the file object
+ * @cl: host client
  *
  * Return:
  *	0 on success
  *	-EINVAL when ctrl credits are <= 0
  */
-static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
+static int mei_cl_tx_flow_ctrl_creds_reduce(struct mei_cl *cl)
 {
 	if (WARN_ON(!cl || !cl->me_cl))
 		return -EINVAL;
@@ -1185,13 +1184,13 @@ static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
 		return 0;
 
 	if (mei_cl_is_single_recv_buf(cl)) {
-		if (WARN_ON(cl->me_cl->mei_flow_ctrl_creds <= 0))
+		if (WARN_ON(cl->me_cl->tx_flow_ctrl_creds <= 0))
 			return -EINVAL;
-		cl->me_cl->mei_flow_ctrl_creds--;
+		cl->me_cl->tx_flow_ctrl_creds--;
 	} else {
-		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+		if (WARN_ON(cl->tx_flow_ctrl_creds <= 0))
 			return -EINVAL;
-		cl->mei_flow_ctrl_creds--;
+		cl->tx_flow_ctrl_creds--;
 	}
 	return 0;
 }
@@ -1511,7 +1510,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_tx_flow_ctrl_creds(cl) : 1;
 	if (rets < 0)
 		return rets;
 
@@ -1559,7 +1558,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 	cb->completed = mei_hdr.msg_complete == 1;
 
 	if (first_chunk) {
-		if (mei_cl_flow_ctrl_reduce(cl))
+		if (mei_cl_tx_flow_ctrl_creds_reduce(cl))
 			return -EIO;
 	}
 
@@ -1617,7 +1616,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_tx_flow_ctrl_creds(cl);
 	if (rets < 0)
 		goto err;
 
@@ -1645,7 +1644,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 	if (rets)
 		goto err;
 
-	rets = mei_cl_flow_ctrl_reduce(cl);
+	rets = mei_cl_tx_flow_ctrl_creds_reduce(cl);
 	if (rets)
 		goto err;
 
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index b1697a329af1..c8e8a8d22019 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -340,7 +340,7 @@ static int mei_hbm_me_cl_add(struct mei_device *dev,
 
 	me_cl->props = res->client_properties;
 	me_cl->client_id = res->me_addr;
-	me_cl->mei_flow_ctrl_creds = 0;
+	me_cl->tx_flow_ctrl_creds = 0;
 
 	mei_me_cl_add(dev, me_cl);
 
@@ -637,23 +637,22 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
 }
 
 /**
- * mei_hbm_add_single_flow_creds - adds single buffer credentials.
+ * mei_hbm_add_single_tx_flow_ctrl_creds - adds single buffer credentials.
  *
  * @dev: the device structure
- * @flow: flow control.
+ * @fctrl: flow control response bus message
  *
  * Return: 0 on success, < 0 otherwise
  */
-static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
-				  struct hbm_flow_control *flow)
+static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev,
+						 struct hbm_flow_control *fctrl)
 {
 	struct mei_me_client *me_cl;
 	int rets;
 
-	me_cl = mei_me_cl_by_id(dev, flow->me_addr);
+	me_cl = mei_me_cl_by_id(dev, fctrl->me_addr);
 	if (!me_cl) {
-		dev_err(dev->dev, "no such me client %d\n",
-			flow->me_addr);
+		dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr);
 		return -ENOENT;
 	}
 
@@ -662,9 +661,9 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
 		goto out;
 	}
 
-	me_cl->mei_flow_ctrl_creds++;
+	me_cl->tx_flow_ctrl_creds++;
 	dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
-	    flow->me_addr, me_cl->mei_flow_ctrl_creds);
+		fctrl->me_addr, me_cl->tx_flow_ctrl_creds);
 
 	rets = 0;
 out:
@@ -676,24 +675,24 @@ out:
  * mei_hbm_cl_flow_control_res - flow control response from me
  *
  * @dev: the device structure
- * @flow_control: flow control response bus message
+ * @fctrl: flow control response bus message
  */
-static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
-					struct hbm_flow_control *flow_control)
+static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev,
+					       struct hbm_flow_control *fctrl)
 {
 	struct mei_cl *cl;
 
-	if (!flow_control->host_addr) {
+	if (!fctrl->host_addr) {
 		/* single receive buffer */
-		mei_hbm_add_single_flow_creds(dev, flow_control);
+		mei_hbm_add_single_tx_flow_ctrl_creds(dev, fctrl);
 		return;
 	}
 
-	cl = mei_hbm_cl_find_by_cmd(dev, flow_control);
+	cl = mei_hbm_cl_find_by_cmd(dev, fctrl);
 	if (cl) {
-		cl->mei_flow_ctrl_creds++;
+		cl->tx_flow_ctrl_creds++;
 		cl_dbg(dev, cl, "flow control creds = %d.\n",
-				cl->mei_flow_ctrl_creds);
+				cl->tx_flow_ctrl_creds);
 	}
 }
 
@@ -1023,7 +1022,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
 
 	struct mei_hbm_cl_cmd *cl_cmd;
 	struct hbm_client_connect_request *disconnect_req;
-	struct hbm_flow_control *flow_control;
+	struct hbm_flow_control *fctrl;
 
 	/* read the message to our buffer */
 	BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
@@ -1103,8 +1102,8 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
 	case MEI_FLOW_CONTROL_CMD:
 		dev_dbg(dev->dev, "hbm: client flow control response: message received.\n");
 
-		flow_control = (struct hbm_flow_control *) mei_msg;
-		mei_hbm_cl_flow_control_res(dev, flow_control);
+		fctrl = (struct hbm_flow_control *)mei_msg;
+		mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl);
 		break;
 
 	case MEI_PG_ISOLATION_ENTRY_RES_CMD:
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 8bdb28054423..7c8fa8d70e11 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -144,7 +144,7 @@ struct mei_fw_status {
  * @refcnt: struct reference count
  * @props: client properties
  * @client_id: me client id
- * @mei_flow_ctrl_creds: flow control credits
+ * @tx_flow_ctrl_creds: flow control credits
  * @connect_count: number connections to this client
  * @bus_added: added to bus
  */
@@ -153,7 +153,7 @@ struct mei_me_client {
 	struct kref refcnt;
 	struct mei_client_properties props;
 	u8 client_id;
-	u8 mei_flow_ctrl_creds;
+	u8 tx_flow_ctrl_creds;
 	u8 connect_count;
 	u8 bus_added;
 };
@@ -202,7 +202,7 @@ struct mei_cl_cb {
  * @me_cl: fw client connected
  * @fp: file associated with client
  * @host_client_id: host id
- * @mei_flow_ctrl_creds: transmit flow credentials
+ * @tx_flow_ctrl_creds: transmit flow credentials
  * @rx_flow_ctrl_creds: receive flow credentials
  * @timer_count:  watchdog timer for operation completion
  * @notify_en: notification - enabled/disabled
@@ -226,7 +226,7 @@ struct mei_cl {
 	struct mei_me_client *me_cl;
 	const struct file *fp;
 	u8 host_client_id;
-	u8 mei_flow_ctrl_creds;
+	u8 tx_flow_ctrl_creds;
 	u8 rx_flow_ctrl_creds;
 	u8 timer_count;
 	u8 notify_en;
-- 
2.7.4

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

* [char-misc-next v2 5/9] mei: add wrapper for queuing control commands.
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
                   ` (3 preceding siblings ...)
  2016-07-25 22:06 ` [char-misc-next v2 4/9] mei: use consistent naming for TX control flow credits Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 6/9] mei: enqueue consecutive reads Tomas Winkler
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

Enclose the boiler plate code of allocating a control/hbm command cb
and enqueueing it onto ctrl_wr.list in a convenient wrapper
mei_cl_enqueue_ctrl_wr_cb().

This is a preparatory patch for enabling consecutive reads.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: replace 0 by mei_cl_mtu(cldev->cl) in bus.c

 drivers/misc/mei/amthif.c |  7 ++---
 drivers/misc/mei/bus.c    |  4 +--
 drivers/misc/mei/client.c | 78 ++++++++++++++++++++++++++++++-----------------
 drivers/misc/mei/client.h |  5 +--
 drivers/misc/mei/hbm.c    |  4 +--
 drivers/misc/mei/main.c   |  2 +-
 6 files changed, 61 insertions(+), 39 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 227fd5a816a6..e8029235504d 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -188,20 +188,19 @@ out:
  * mei_amthif_read_start - queue message for sending read credential
  *
  * @cl: host client
- * @file: file pointer of message recipient
+ * @fp: file pointer of message recipient
  *
  * Return: 0 on success, <0 on failure.
  */
-static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file)
+static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp)
 {
 	struct mei_device *dev = cl->dev;
 	struct mei_cl_cb *cb;
 
-	cb = mei_cl_alloc_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, file);
+	cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp);
 	if (!cb)
 		return -ENOMEM;
 
-	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 	cl->rx_flow_ctrl_creds++;
 
 	dev->iamthif_state = MEI_IAMTHIF_READING;
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 9c404dc8eada..cdf13f6d2697 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -235,7 +235,7 @@ static void mei_cl_bus_event_work(struct work_struct *work)
 	/* Prepare for the next read */
 	if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
 		mutex_lock(&bus->device_lock);
-		mei_cl_read_start(cldev->cl, 0, NULL);
+		mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
 		mutex_unlock(&bus->device_lock);
 	}
 }
@@ -325,7 +325,7 @@ int mei_cldev_register_event_cb(struct mei_cl_device *cldev,
 
 	if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
 		mutex_lock(&bus->device_lock);
-		ret = mei_cl_read_start(cldev->cl, 0, NULL);
+		ret = mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
 		mutex_unlock(&bus->device_lock);
 		if (ret && ret != -EBUSY)
 			return ret;
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 89425a8795a8..c924ba92c834 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -358,8 +358,9 @@ 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,
-				 const struct file *fp)
+static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl,
+					enum mei_cb_file_ops type,
+					const struct file *fp)
 {
 	struct mei_cl_cb *cb;
 
@@ -430,12 +431,12 @@ static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
  * 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,
+				  enum mei_cb_file_ops fop_type,
 				  const struct file *fp)
 {
 	struct mei_cl_cb *cb;
 
-	cb = mei_io_cb_init(cl, type, fp);
+	cb = mei_io_cb_init(cl, fop_type, fp);
 	if (!cb)
 		return NULL;
 
@@ -453,6 +454,36 @@ struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
 }
 
 /**
+ * mei_cl_enqueue_ctrl_wr_cb - a convenient wrapper for allocating
+ *     and enqueuing of the control commands cb
+ *
+ * @cl: host client
+ * @length: size of the buffer
+ * @type: operation type
+ * @fp: associated file pointer (might be NULL)
+ *
+ * Return: cb on success and NULL on failure
+ * Locking: called under "dev->device_lock" lock
+ */
+struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
+					    enum mei_cb_file_ops fop_type,
+					    const struct file *fp)
+{
+	struct mei_cl_cb *cb;
+
+	/* for RX always allocate at least client's mtu */
+	if (length)
+		length = max_t(size_t, length, mei_cl_mtu(cl));
+
+	cb = mei_cl_alloc_cb(cl, length, fop_type, fp);
+	if (!cb)
+		return NULL;
+
+	list_add_tail(&cb->list, &cl->dev->ctrl_wr_list.list);
+	return cb;
+}
+
+/**
  * mei_cl_read_cb - find this cl's callback in the read list
  *     for a specific file
  *
@@ -848,13 +879,11 @@ static int __mei_cl_disconnect(struct mei_cl *cl)
 
 	cl->state = MEI_FILE_DISCONNECTING;
 
-	cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
-	rets = cb ? 0 : -ENOMEM;
-	if (rets)
+	cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT, NULL);
+	if (!cb) {
+		rets = -ENOMEM;
 		goto out;
-
-	cl_dbg(dev, cl, "add disconnect cb to control write list\n");
-	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+	}
 
 	if (mei_hbuf_acquire(dev)) {
 		rets = mei_cl_send_disconnect(cl, cb);
@@ -1023,14 +1052,14 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: host client
  * @me_cl: me client
- * @file: pointer to file structure
+ * @fp: pointer to file structure
  *
  * Locking: called under "dev->device_lock" lock
  *
  * Return: 0 on success, <0 on failure.
  */
 int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
-		  const struct file *file)
+		   const struct file *fp)
 {
 	struct mei_device *dev;
 	struct mei_cl_cb *cb;
@@ -1057,12 +1086,11 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
 		goto nortpm;
 	}
 
-	cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
-	rets = cb ? 0 : -ENOMEM;
-	if (rets)
+	cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_CONNECT, fp);
+	if (!cb) {
+		rets = -ENOMEM;
 		goto out;
-
-	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+	}
 
 	/* run hbuf acquire last so we don't have to undo */
 	if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
@@ -1265,7 +1293,7 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
  * mei_cl_notify_request - send notification stop/start request
  *
  * @cl: host client
- * @file: associate request with file
+ * @fp: associate request with file
  * @request: 1 for start or 0 for stop
  *
  * Locking: called under "dev->device_lock" lock
@@ -1273,7 +1301,7 @@ 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,
-			  const struct file *file, u8 request)
+			  const struct file *fp, u8 request)
 {
 	struct mei_device *dev;
 	struct mei_cl_cb *cb;
@@ -1298,7 +1326,7 @@ int mei_cl_notify_request(struct mei_cl *cl,
 	}
 
 	fop_type = mei_cl_notify_req2fop(request);
-	cb = mei_io_cb_init(cl, fop_type, file);
+	cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, fop_type, fp);
 	if (!cb) {
 		rets = -ENOMEM;
 		goto out;
@@ -1309,9 +1337,7 @@ int mei_cl_notify_request(struct mei_cl *cl,
 			rets = -ENODEV;
 			goto out;
 		}
-		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
-	} else {
-		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+		list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
 	}
 
 	mutex_unlock(&dev->device_lock);
@@ -1443,14 +1469,10 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
 	if (cl->rx_flow_ctrl_creds)
 		return -EBUSY;
 
-	/* always allocate at least client max message */
-	length = max_t(size_t, length, mei_cl_mtu(cl));
-	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
+	cb = mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, fp);
 	if (!cb)
 		return -ENOMEM;
 
-	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
-
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
 		pm_runtime_put_noidle(dev->dev);
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 16466aa40cbd..d2bfabecd882 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -82,8 +82,6 @@ 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,
-				 const struct file *fp);
 void mei_io_cb_free(struct mei_cl_cb *priv_cb);
 
 /**
@@ -116,6 +114,9 @@ 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,
 				  const struct file *fp);
+struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
+					    enum mei_cb_file_ops type,
+					    const struct file *fp);
 int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp);
 
 /*
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index c8e8a8d22019..4b9495f0394c 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -871,10 +871,10 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
 		cl->state = MEI_FILE_DISCONNECTING;
 		cl->timer_count = 0;
 
-		cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT_RSP, NULL);
+		cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT_RSP,
+					       NULL);
 		if (!cb)
 			return -ENOMEM;
-		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 	}
 	return 0;
 }
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index d7ef5edf044a..d698ba32357c 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -628,7 +628,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
 		if (!list_empty(&cl->rd_completed))
 			mask |= POLLIN | POLLRDNORM;
 		else
-			mei_cl_read_start(cl, 0, file);
+			mei_cl_read_start(cl, mei_cl_mtu(cl), file);
 	}
 
 out:
-- 
2.7.4

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

* [char-misc-next v2 6/9] mei: enqueue consecutive reads
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
                   ` (4 preceding siblings ...)
  2016-07-25 22:06 ` [char-misc-next v2 5/9] mei: add wrapper for queuing control commands Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 7/9] mei: amthif: drop mei_amthif_read Tomas Winkler
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

The FW supports only one pending read per host client, in order to
support  issuing of consecutive reads the driver  queues read requests
internally and send them to the firmware after pending one has
completed.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: resend
 drivers/misc/mei/interrupt.c |  3 +++
 drivers/misc/mei/main.c      | 39 +++++++++++++++++++--------------------
 2 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 36382d782e20..bf745e03f21e 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -209,6 +209,9 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
 	int slots;
 	int ret;
 
+	if (!list_empty(&cl->rd_pending))
+		return 0;
+
 	msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
 	slots = mei_hbuf_empty_slots(dev);
 
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index d698ba32357c..650061b6ab9b 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -139,9 +139,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
 	struct mei_cl *cl = file->private_data;
 	struct mei_device *dev;
 	struct mei_cl_cb *cb = NULL;
+	bool nonblock = !!(file->f_flags & O_NONBLOCK);
 	int rets;
-	int err;
-
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -ENODEV;
@@ -177,25 +176,29 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
 	if (*offset > 0)
 		*offset = 0;
 
-	err = mei_cl_read_start(cl, length, file);
-	if (err && err != -EBUSY) {
-		cl_dbg(dev, cl, "mei start read failure status = %d\n", err);
-		rets = err;
+	rets = mei_cl_read_start(cl, length, file);
+	if (rets && rets != -EBUSY) {
+		cl_dbg(dev, cl, "mei start read failure status = %d\n", rets);
 		goto out;
 	}
 
-	/* synchronized under device mutex */
-	if (!waitqueue_active(&cl->rx_wait)) {
-		if (file->f_flags & O_NONBLOCK) {
-			rets = -EAGAIN;
-			goto out;
-		}
+	if (nonblock) {
+		rets = -EAGAIN;
+		goto out;
+	}
+
+	if (rets == -EBUSY &&
+	    !mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, file)) {
+		rets = -ENOMEM;
+		goto out;
+	}
 
+	do {
 		mutex_unlock(&dev->device_lock);
 
 		if (wait_event_interruptible(cl->rx_wait,
-				(!list_empty(&cl->rd_completed)) ||
-				(!mei_cl_is_connected(cl)))) {
+					     (!list_empty(&cl->rd_completed)) ||
+					     (!mei_cl_is_connected(cl)))) {
 
 			if (signal_pending(current))
 				return -EINTR;
@@ -207,13 +210,9 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
 			rets = -ENODEV;
 			goto out;
 		}
-	}
 
-	cb = mei_cl_read_cb(cl, file);
-	if (!cb) {
-		rets = 0;
-		goto out;
-	}
+		cb = mei_cl_read_cb(cl, file);
+	} while (!cb);
 
 copy_buffer:
 	/* now copy the data to user space */
-- 
2.7.4

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

* [char-misc-next v2 7/9] mei: amthif: drop mei_amthif_read
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
                   ` (5 preceding siblings ...)
  2016-07-25 22:06 ` [char-misc-next v2 6/9] mei: enqueue consecutive reads Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 8/9] mei: drop unused file transaction states Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 9/9] mei: amthif: fix deadlock in initialization during a reset Tomas Winkler
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, Tomas Winkler

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

mei_amthif_read have only one difference from mei_read, it is not
calling mei_read_start().
Make mei_read_start return immediately for amthif client and drop the
special mei_amthif_read function.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: resend
 drivers/misc/mei/amthif.c  | 100 ---------------------------------------------
 drivers/misc/mei/client.c  |   2 +-
 drivers/misc/mei/main.c    |   5 ---
 drivers/misc/mei/mei_dev.h |   3 --
 4 files changed, 1 insertion(+), 109 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index e8029235504d..2222b60e9208 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -85,106 +85,6 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 }
 
 /**
- * mei_amthif_read - read data from AMTHIF client
- *
- * @dev: the device structure
- * @file: pointer to file object
- * @ubuf: pointer to user data in user space
- * @length: data length to read
- * @offset: data read offset
- *
- * Locking: called under "dev->device_lock" lock
- *
- * Return:
- *  returned data length on success,
- *  zero if no data to read,
- *  negative on failure.
- */
-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_cl_read_cb(cl, file);
-
-	/* Check for if we can block or not*/
-	if (cb == NULL && file->f_flags & O_NONBLOCK)
-		return -EAGAIN;
-
-
-	dev_dbg(dev->dev, "waiting for amthif data\n");
-	while (cb == NULL) {
-		/* unlock the Mutex */
-		mutex_unlock(&dev->device_lock);
-
-		wait_ret = wait_event_interruptible(cl->rx_wait,
-					!list_empty(&cl->rd_completed) ||
-					!mei_cl_is_connected(cl));
-
-		/* Locking again the Mutex */
-		mutex_lock(&dev->device_lock);
-
-		if (wait_ret)
-			return -ERESTARTSYS;
-
-		if (!mei_cl_is_connected(cl)) {
-			rets = -ENODEV;
-			goto out;
-		}
-
-		cb = mei_cl_read_cb(cl, file);
-	}
-
-	if (cb->status) {
-		rets = cb->status;
-		dev_dbg(dev->dev, "read operation failed %d\n", rets);
-		goto free;
-	}
-
-	dev_dbg(dev->dev, "Got amthif data\n");
-	/* 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 <= *offset) {
-		/* end of the message has been reached */
-		list_del_init(&cb->list);
-		rets = 0;
-		goto free;
-	}
-		/* else means that not full buffer will be read and do not
-		 * remove message from deletion list
-		 */
-
-	dev_dbg(dev->dev, "amthif cb->buf.size - %zu cb->buf_idx - %zu\n",
-		cb->buf.size, cb->buf_idx);
-
-	/* length is being truncated to PAGE_SIZE, however,
-	 * the buf_idx may point beyond */
-	length = min_t(size_t, length, (cb->buf_idx - *offset));
-
-	if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
-		dev_dbg(dev->dev, "failed to copy data to userland\n");
-		rets = -EFAULT;
-	} else {
-		rets = length;
-		if ((*offset + length) < cb->buf_idx) {
-			*offset += length;
-			goto out;
-		}
-	}
-free:
-	dev_dbg(dev->dev, "free amthif cb memory.\n");
-	*offset = 0;
-	mei_io_cb_free(cb);
-out:
-	return rets;
-}
-
-/**
  * mei_amthif_read_start - queue message for sending read credential
  *
  * @cl: host client
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index c924ba92c834..45a7652820cf 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1462,7 +1462,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
 		return  -ENOTTY;
 	}
 
-	if (mei_cl_is_fixed_address(cl))
+	if (mei_cl_is_fixed_address(cl) || cl == &dev->iamthif_cl)
 		return 0;
 
 	/* HW currently supports only one pending read */
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 650061b6ab9b..fa50635512e8 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -164,11 +164,6 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
 		goto out;
 	}
 
-	if (cl == &dev->iamthif_cl) {
-		rets = mei_amthif_read(dev, file, ubuf, length, offset);
-		goto out;
-	}
-
 	cb = mei_cl_read_cb(cl, file);
 	if (cb)
 		goto copy_buffer;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 7c8fa8d70e11..2ef1ad6c391a 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -564,9 +564,6 @@ void mei_amthif_reset_params(struct mei_device *dev);
 
 int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
 
-int mei_amthif_read(struct mei_device *dev, struct file *file,
-		char __user *ubuf, size_t length, loff_t *offset);
-
 unsigned int mei_amthif_poll(struct file *file, poll_table *wait);
 
 int mei_amthif_release(struct mei_device *dev, struct file *file);
-- 
2.7.4

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

* [char-misc-next v2 8/9] mei: drop unused file transaction states
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
                   ` (6 preceding siblings ...)
  2016-07-25 22:06 ` [char-misc-next v2 7/9] mei: amthif: drop mei_amthif_read Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  2016-07-25 22:06 ` [char-misc-next v2 9/9] mei: amthif: fix deadlock in initialization during a reset Tomas Winkler
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 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>
---
V2: resend
 drivers/misc/mei/mei_dev.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 2ef1ad6c391a..397ae2b45c9e 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -87,9 +87,6 @@ enum mei_file_transaction_states {
 	MEI_IDLE,
 	MEI_WRITING,
 	MEI_WRITE_COMPLETE,
-	MEI_FLOW_CONTROL,
-	MEI_READING,
-	MEI_READ_COMPLETE
 };
 
 /**
-- 
2.7.4

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

* [char-misc-next v2 9/9] mei: amthif: fix deadlock in initialization during a reset
  2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
                   ` (7 preceding siblings ...)
  2016-07-25 22:06 ` [char-misc-next v2 8/9] mei: drop unused file transaction states Tomas Winkler
@ 2016-07-25 22:06 ` Tomas Winkler
  8 siblings, 0 replies; 10+ messages in thread
From: Tomas Winkler @ 2016-07-25 22:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: Alexander Usyskin, linux-kernel, stable, Tomas Winkler

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

The device lock was unnecessary obtained in bus rescan work before the
amthif client search.  That causes incorrect lock ordering and task
hang:
...
[88004.613213] INFO: task kworker/1:14:21832 blocked for more than 120 seconds.
...
[88004.645934] Workqueue: events mei_cl_bus_rescan_work
...

The correct lock order is
 cl_bus_lock
  device_lock
   me_clients_rwsem

Move device_lock into amthif init function that called
after me_clients_rwsem is released.

This fixes regression introduced by commit:
commit 025fb792bac3 ("mei: split amthif client init from end of clients enumeration")

Cc: <stable@vger.kernel.org> # 4.6+
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: new in the seriese

 drivers/misc/mei/amthif.c | 12 +++++++++---
 drivers/misc/mei/bus.c    |  2 --
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 2222b60e9208..082462ea90c9 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -66,8 +66,12 @@ 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;
+	mutex_lock(&dev->device_lock);
+
+	if (mei_cl_is_connected(cl)) {
+		ret = 0;
+		goto out;
+	}
 
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
 
@@ -76,11 +80,13 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
 	ret = mei_cl_link(cl);
 	if (ret < 0) {
 		dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
-		return ret;
+		goto out;
 	}
 
 	ret = mei_cl_connect(cl, me_cl, NULL);
 
+out:
+	mutex_unlock(&dev->device_lock);
 	return ret;
 }
 
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index cdf13f6d2697..8cac7ef9ad0d 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -984,12 +984,10 @@ void mei_cl_bus_rescan_work(struct work_struct *work)
 		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);
 }
-- 
2.7.4

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

end of thread, other threads:[~2016-07-25 22:10 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-25 22:06 [char-misc-next v2 0/9] mei: rx enhancements Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 1/9] mei: drop redundant krealloc and checks in irq read Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 2/9] mei: prepare read cb for fixed address clients on the receive path only Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 3/9] mei: rx flow control counter Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 4/9] mei: use consistent naming for TX control flow credits Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 5/9] mei: add wrapper for queuing control commands Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 6/9] mei: enqueue consecutive reads Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 7/9] mei: amthif: drop mei_amthif_read Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 8/9] mei: drop unused file transaction states Tomas Winkler
2016-07-25 22:06 ` [char-misc-next v2 9/9] mei: amthif: fix deadlock in initialization during a reset 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).