mei: support for fixed address clients
authorAlexander Usyskin <alexander.usyskin@intel.com>
Mon, 4 May 2015 06:43:56 +0000 (09:43 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 24 May 2015 18:13:48 +0000 (11:13 -0700)
Fixed address is simplified FW client that doesn't require
connection and doesn't support flow control.
So it can be only one host client per fixed FW client.
Fixed client access is available only for drivers on mei bus,
connection from user-space is blocked.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/hbm.c
drivers/misc/mei/interrupt.c

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