summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Usyskin <alexander.usyskin@intel.com>2016-01-07 12:46:36 (GMT)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-07 06:06:43 (GMT)
commit13cf988562b0c7f06e0016bea2b5304358397702 (patch)
treed3da0573389d0625ecf182028762978cece63365
parent2bcfdc23c6a418b441a1d17f237e9ea347e2fb1f (diff)
downloadlinux-13cf988562b0c7f06e0016bea2b5304358397702.tar.xz
mei: prevent queuing new flow control credit.
The MEI FW can receive only one flow control for read. Currently the driver only checks if a flow control credit was already sent and read is pending in the rd_pending queue, but it also has to check if flow control credit already queued in the write control queue to prevent sending more than one flow control credits. Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/misc/mei/client.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index a6c87c7..72e3261 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1422,6 +1422,25 @@ 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
@@ -1445,7 +1464,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
return -ENODEV;
/* HW currently supports only one pending read */
- if (!list_empty(&cl->rd_pending))
+ if (!list_empty(&cl->rd_pending) || mei_cl_is_read_fc_cb(cl))
return -EBUSY;
if (!mei_me_cl_is_active(cl->me_cl)) {