blob: 058dd6917805024d259e4ea17c4845e48a8f42cb [file] [log] [blame]
Tomas Winkler19838fb2012-11-01 21:17:15 +02001/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2012, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/fs.h>
19#include <linux/errno.h>
20#include <linux/types.h>
21#include <linux/fcntl.h>
Tomas Winkler19838fb2012-11-01 21:17:15 +020022#include <linux/ioctl.h>
23#include <linux/cdev.h>
24#include <linux/list.h>
25#include <linux/delay.h>
26#include <linux/sched.h>
27#include <linux/uuid.h>
28#include <linux/jiffies.h>
29#include <linux/uaccess.h>
Tomas Winkler1f180352014-09-29 16:31:46 +030030#include <linux/slab.h>
Tomas Winkler19838fb2012-11-01 21:17:15 +020031
Tomas Winkler47a73802012-12-25 19:06:03 +020032#include <linux/mei.h>
Tomas Winkler19838fb2012-11-01 21:17:15 +020033
34#include "mei_dev.h"
Tomas Winkler0edb23f2013-01-08 23:07:12 +020035#include "hbm.h"
Tomas Winkler90e0b5f2013-01-08 23:07:14 +020036#include "client.h"
Tomas Winkler19838fb2012-11-01 21:17:15 +020037
Tomas Winkler1a1aca42013-01-08 23:07:21 +020038const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
39 0xac, 0xa8, 0x46, 0xe0,
40 0xff, 0x65, 0x81, 0x4c);
Tomas Winkler19838fb2012-11-01 21:17:15 +020041
42/**
43 * mei_amthif_reset_params - initializes mei device iamthif
44 *
45 * @dev: the device structure
46 */
47void mei_amthif_reset_params(struct mei_device *dev)
48{
49 /* reset iamthif parameters. */
50 dev->iamthif_current_cb = NULL;
Tomas Winkler19838fb2012-11-01 21:17:15 +020051 dev->iamthif_canceled = false;
Tomas Winkler19838fb2012-11-01 21:17:15 +020052 dev->iamthif_state = MEI_IAMTHIF_IDLE;
Alexander Usyskin4a704572013-09-02 13:29:47 +030053 dev->iamthif_stall_timer = 0;
Tomas Winkler22f96a02013-09-16 23:44:47 +030054 dev->iamthif_open_count = 0;
Tomas Winkler19838fb2012-11-01 21:17:15 +020055}
56
57/**
Masanari Iida393b1482013-04-05 01:05:05 +090058 * mei_amthif_host_init - mei initialization amthif client.
Tomas Winkler19838fb2012-11-01 21:17:15 +020059 *
60 * @dev: the device structure
Alexander Usyskind49ed642015-05-04 09:43:54 +030061 * @me_cl: me client
Tomas Winkler19838fb2012-11-01 21:17:15 +020062 *
Alexander Usyskince231392014-09-29 16:31:50 +030063 * Return: 0 on success, <0 on failure.
Tomas Winkler19838fb2012-11-01 21:17:15 +020064 */
Alexander Usyskind49ed642015-05-04 09:43:54 +030065int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
Tomas Winkler19838fb2012-11-01 21:17:15 +020066{
Tomas Winkler781d0d82013-01-08 23:07:22 +020067 struct mei_cl *cl = &dev->iamthif_cl;
Tomas Winklerd3208322014-08-24 12:08:55 +030068 int ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +020069
Tomas Winkler6222f7b2013-01-08 23:07:23 +020070 dev->iamthif_state = MEI_IAMTHIF_IDLE;
71
Tomas Winkler781d0d82013-01-08 23:07:22 +020072 mei_cl_init(cl, dev);
Tomas Winkler19838fb2012-11-01 21:17:15 +020073
Tomas Winkler781d0d82013-01-08 23:07:22 +020074 ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
Tomas Winkler781d0d82013-01-08 23:07:22 +020075 if (ret < 0) {
Tomas Winkler79563db2015-01-11 00:07:16 +020076 dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
Alexander Usyskind49ed642015-05-04 09:43:54 +030077 return ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +020078 }
Tomas Winkler781d0d82013-01-08 23:07:22 +020079
Alexander Usyskind49ed642015-05-04 09:43:54 +030080 ret = mei_cl_connect(cl, me_cl, NULL);
Tomas Winkler64092852014-02-17 15:13:21 +020081
82 dev->iamthif_state = MEI_IAMTHIF_IDLE;
83
84 return ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +020085}
86
87/**
Tomas Winkler19838fb2012-11-01 21:17:15 +020088 * mei_amthif_read - read data from AMTHIF client
89 *
90 * @dev: the device structure
Tomas Winkler19838fb2012-11-01 21:17:15 +020091 * @file: pointer to file object
Alexander Usyskina8605ea2014-09-29 16:31:49 +030092 * @ubuf: pointer to user data in user space
Tomas Winkler19838fb2012-11-01 21:17:15 +020093 * @length: data length to read
94 * @offset: data read offset
95 *
96 * Locking: called under "dev->device_lock" lock
97 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +030098 * Return:
Tomas Winkler19838fb2012-11-01 21:17:15 +020099 * returned data length on success,
100 * zero if no data to read,
101 * negative on failure.
102 */
103int mei_amthif_read(struct mei_device *dev, struct file *file,
104 char __user *ubuf, size_t length, loff_t *offset)
105{
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200106 struct mei_cl *cl = file->private_data;
Tomas Winklerd3208322014-08-24 12:08:55 +0300107 struct mei_cl_cb *cb;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200108 int rets;
109 int wait_ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200110
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300111 dev_dbg(dev->dev, "checking amthif data\n");
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200112 cb = mei_cl_read_cb(cl, file);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200113
114 /* Check for if we can block or not*/
115 if (cb == NULL && file->f_flags & O_NONBLOCK)
116 return -EAGAIN;
117
118
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300119 dev_dbg(dev->dev, "waiting for amthif data\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200120 while (cb == NULL) {
121 /* unlock the Mutex */
122 mutex_unlock(&dev->device_lock);
123
124 wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200125 !list_empty(&cl->rd_completed));
Tomas Winkler19838fb2012-11-01 21:17:15 +0200126
Alexey Khoroshilove6028db2012-12-22 01:44:16 +0400127 /* Locking again the Mutex */
128 mutex_lock(&dev->device_lock);
129
Tomas Winkler19838fb2012-11-01 21:17:15 +0200130 if (wait_ret)
131 return -ERESTARTSYS;
132
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200133 cb = mei_cl_read_cb(cl, file);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200134 }
135
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200136 if (cb->status) {
137 rets = cb->status;
138 dev_dbg(dev->dev, "read operation failed %d\n", rets);
139 goto free;
140 }
Tomas Winkler19838fb2012-11-01 21:17:15 +0200141
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300142 dev_dbg(dev->dev, "Got amthif data\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200143 /* if the whole message will fit remove it from the list */
144 if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
Tomas Winkler928fa662015-02-10 10:39:45 +0200145 list_del_init(&cb->list);
Alexander Usyskin5ba0bf42016-02-07 23:35:21 +0200146 else if (cb->buf_idx <= *offset) {
Tomas Winkler19838fb2012-11-01 21:17:15 +0200147 /* end of the message has been reached */
Tomas Winkler928fa662015-02-10 10:39:45 +0200148 list_del_init(&cb->list);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200149 rets = 0;
150 goto free;
151 }
152 /* else means that not full buffer will be read and do not
153 * remove message from deletion list
154 */
155
Tomas Winklerf862b6b2016-02-07 23:35:19 +0200156 dev_dbg(dev->dev, "amthif cb->buf.size - %zd cb->buf_idx - %zd\n",
157 cb->buf.size, cb->buf_idx);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200158
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200159 /* length is being truncated to PAGE_SIZE, however,
Tomas Winkler19838fb2012-11-01 21:17:15 +0200160 * the buf_idx may point beyond */
161 length = min_t(size_t, length, (cb->buf_idx - *offset));
162
Tomas Winkler5db75142015-02-10 10:39:42 +0200163 if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300164 dev_dbg(dev->dev, "failed to copy data to userland\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200165 rets = -EFAULT;
Tomas Winkler34e267d2014-03-16 14:35:57 +0200166 } else {
Tomas Winkler19838fb2012-11-01 21:17:15 +0200167 rets = length;
168 if ((*offset + length) < cb->buf_idx) {
169 *offset += length;
170 goto out;
171 }
172 }
173free:
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300174 dev_dbg(dev->dev, "free amthif cb memory.\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200175 *offset = 0;
176 mei_io_cb_free(cb);
177out:
178 return rets;
179}
180
181/**
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200182 * mei_amthif_read_start - queue message for sending read credential
183 *
184 * @cl: host client
185 * @file: file pointer of message recipient
186 *
187 * Return: 0 on success, <0 on failure.
188 */
Tomas Winklerf23e2cc2016-02-07 23:35:23 +0200189static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file)
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200190{
191 struct mei_device *dev = cl->dev;
192 struct mei_cl_cb *cb;
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200193 int rets;
194
Tomas Winklerbca67d62015-02-10 10:39:43 +0200195 cb = mei_io_cb_init(cl, MEI_FOP_READ, file);
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200196 if (!cb) {
197 rets = -ENOMEM;
198 goto err;
199 }
200
Alexander Usyskin9e239362015-05-04 09:43:58 +0300201 rets = mei_io_cb_alloc_buf(cb, mei_cl_mtu(cl));
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200202 if (rets)
203 goto err;
204
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200205 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
206
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200207 dev->iamthif_state = MEI_IAMTHIF_READING;
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200208 dev->iamthif_fp = cb->fp;
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200209 dev->iamthif_current_cb = cb;
210
211 return 0;
212err:
213 mei_io_cb_free(cb);
214 return rets;
215}
216
217/**
Tomas Winklerab5c4a52012-11-01 21:17:18 +0200218 * mei_amthif_send_cmd - send amthif command to the ME
Tomas Winkler19838fb2012-11-01 21:17:15 +0200219 *
Tomas Winkler86601722015-02-10 10:39:40 +0200220 * @cl: the host client
Tomas Winkler19838fb2012-11-01 21:17:15 +0200221 * @cb: mei call back struct
222 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300223 * Return: 0 on success, <0 on failure.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200224 */
Tomas Winkler86601722015-02-10 10:39:40 +0200225static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200226{
Tomas Winkler86601722015-02-10 10:39:40 +0200227 struct mei_device *dev;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200228 int ret;
229
Tomas Winkler86601722015-02-10 10:39:40 +0200230 if (!cl->dev || !cb)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200231 return -ENODEV;
232
Tomas Winkler86601722015-02-10 10:39:40 +0200233 dev = cl->dev;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200234
235 dev->iamthif_state = MEI_IAMTHIF_WRITING;
236 dev->iamthif_current_cb = cb;
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200237 dev->iamthif_fp = cb->fp;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200238 dev->iamthif_canceled = false;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200239
Tomas Winkler86601722015-02-10 10:39:40 +0200240 ret = mei_cl_write(cl, cb, false);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200241 if (ret < 0)
242 return ret;
243
Tomas Winkler86601722015-02-10 10:39:40 +0200244 if (cb->completed)
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200245 cb->status = mei_amthif_read_start(cl, cb->fp);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200246
Tomas Winkler19838fb2012-11-01 21:17:15 +0200247 return 0;
248}
249
250/**
Alexander Usyskince231392014-09-29 16:31:50 +0300251 * mei_amthif_run_next_cmd - send next amt command from queue
Tomas Winkler19838fb2012-11-01 21:17:15 +0200252 *
253 * @dev: the device structure
Tomas Winkler86601722015-02-10 10:39:40 +0200254 *
255 * Return: 0 on success, <0 on failure.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200256 */
Tomas Winkler86601722015-02-10 10:39:40 +0200257int mei_amthif_run_next_cmd(struct mei_device *dev)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200258{
Tomas Winkler86601722015-02-10 10:39:40 +0200259 struct mei_cl *cl = &dev->iamthif_cl;
Alexander Usyskin05e314e2014-08-14 17:22:21 +0300260 struct mei_cl_cb *cb;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200261
Tomas Winkler19838fb2012-11-01 21:17:15 +0200262 dev->iamthif_canceled = false;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200263 dev->iamthif_state = MEI_IAMTHIF_IDLE;
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200264 dev->iamthif_fp = NULL;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200265
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300266 dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200267
Alexander Usyskin140c7552014-10-02 13:39:31 +0300268 cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
269 typeof(*cb), list);
270 if (!cb)
Tomas Winkler86601722015-02-10 10:39:40 +0200271 return 0;
272
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200273 list_del_init(&cb->list);
Tomas Winkler86601722015-02-10 10:39:40 +0200274 return mei_amthif_send_cmd(cl, cb);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200275}
276
Tomas Winkler86601722015-02-10 10:39:40 +0200277/**
278 * mei_amthif_write - write amthif data to amthif client
279 *
280 * @cl: host client
281 * @cb: mei call back struct
282 *
283 * Return: 0 on success, <0 on failure.
284 */
285int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
286{
287
288 struct mei_device *dev;
289
290 if (WARN_ON(!cl || !cl->dev))
291 return -ENODEV;
292
293 if (WARN_ON(!cb))
294 return -EINVAL;
295
296 dev = cl->dev;
297
Tomas Winkler86601722015-02-10 10:39:40 +0200298 list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
Alexander Usyskin5cf8b2a2016-02-07 23:35:25 +0200299
300 /*
301 * The previous request is still in processing, queue this one.
302 */
303 if (dev->iamthif_state > MEI_IAMTHIF_IDLE &&
304 dev->iamthif_state < MEI_IAMTHIF_READ_COMPLETE)
305 return 0;
306
Tomas Winkler86601722015-02-10 10:39:40 +0200307 return mei_amthif_run_next_cmd(dev);
308}
Tomas Winkler744f0f22012-11-11 17:38:02 +0200309
Tomas Winkler1d9013f2015-03-27 00:27:57 +0200310/**
311 * mei_amthif_poll - the amthif poll function
312 *
313 * @dev: the device structure
314 * @file: pointer to file structure
315 * @wait: pointer to poll_table structure
316 *
317 * Return: poll mask
318 *
319 * Locking: called under "dev->device_lock" lock
320 */
Tomas Winkler744f0f22012-11-11 17:38:02 +0200321
322unsigned int mei_amthif_poll(struct mei_device *dev,
323 struct file *file, poll_table *wait)
324{
325 unsigned int mask = 0;
Tomas Winklerb950ac12013-07-25 20:15:53 +0300326
Tomas Winkler744f0f22012-11-11 17:38:02 +0200327 poll_wait(file, &dev->iamthif_cl.wait, wait);
Tomas Winklerb950ac12013-07-25 20:15:53 +0300328
Tomas Winkler1d9013f2015-03-27 00:27:57 +0200329 if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200330 dev->iamthif_fp == file) {
Tomas Winklerb950ac12013-07-25 20:15:53 +0300331
Tomas Winkler1d9013f2015-03-27 00:27:57 +0200332 mask |= POLLIN | POLLRDNORM;
Tomas Winkler744f0f22012-11-11 17:38:02 +0200333 mei_amthif_run_next_cmd(dev);
334 }
Tomas Winklerb950ac12013-07-25 20:15:53 +0300335
Tomas Winkler744f0f22012-11-11 17:38:02 +0200336 return mask;
337}
338
339
340
Tomas Winkler19838fb2012-11-01 21:17:15 +0200341/**
Tomas Winkler9d098192014-02-19 17:35:48 +0200342 * mei_amthif_irq_write - write iamthif command in irq thread context.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200343 *
Tomas Winkler19838fb2012-11-01 21:17:15 +0200344 * @cl: private data of the file object.
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300345 * @cb: callback block.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200346 * @cmpl_list: complete list.
347 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300348 * Return: 0, OK; otherwise, error.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200349 */
Tomas Winkler9d098192014-02-19 17:35:48 +0200350int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
351 struct mei_cl_cb *cmpl_list)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200352{
Tomas Winkler86601722015-02-10 10:39:40 +0200353 int ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200354
Tomas Winkler86601722015-02-10 10:39:40 +0200355 ret = mei_cl_irq_write(cl, cb, cmpl_list);
356 if (ret)
357 return ret;
Tomas Winkler136698e2013-09-16 23:44:44 +0300358
Tomas Winkler86601722015-02-10 10:39:40 +0200359 if (cb->completed)
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200360 cb->status = mei_amthif_read_start(cl, cb->fp);
Tomas Winkler24c656e2012-11-18 15:13:17 +0200361
Tomas Winkler19838fb2012-11-01 21:17:15 +0200362 return 0;
363}
364
365/**
Alexander Usyskince231392014-09-29 16:31:50 +0300366 * mei_amthif_irq_read_msg - read routine after ISR to
Tomas Winkler1a1aca42013-01-08 23:07:21 +0200367 * handle the read amthif message
Tomas Winkler19838fb2012-11-01 21:17:15 +0200368 *
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200369 * @cl: mei client
Tomas Winkler1a1aca42013-01-08 23:07:21 +0200370 * @mei_hdr: header of amthif message
Tomas Winkler331e4182015-02-10 10:39:41 +0200371 * @cmpl_list: completed callbacks list
Tomas Winkler19838fb2012-11-01 21:17:15 +0200372 *
Tomas Winkler331e4182015-02-10 10:39:41 +0200373 * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
Tomas Winkler19838fb2012-11-01 21:17:15 +0200374 */
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200375int mei_amthif_irq_read_msg(struct mei_cl *cl,
Tomas Winkler5ceb46e2013-04-19 21:16:53 +0300376 struct mei_msg_hdr *mei_hdr,
Tomas Winkler331e4182015-02-10 10:39:41 +0200377 struct mei_cl_cb *cmpl_list)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200378{
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200379 struct mei_device *dev;
Tomas Winkler331e4182015-02-10 10:39:41 +0200380 int ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200381
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200382 dev = cl->dev;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200383
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200384 if (dev->iamthif_state != MEI_IAMTHIF_READING)
Tomas Winkler331e4182015-02-10 10:39:41 +0200385 return 0;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200386
Tomas Winkler331e4182015-02-10 10:39:41 +0200387 ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
388 if (ret)
389 return ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200390
391 if (!mei_hdr->msg_complete)
392 return 0;
393
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300394 dev_dbg(dev->dev, "completed amthif read.\n ");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200395 dev->iamthif_current_cb = NULL;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200396 dev->iamthif_stall_timer = 0;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200397
Tomas Winkler19838fb2012-11-01 21:17:15 +0200398 return 0;
399}
400
401/**
402 * mei_amthif_complete - complete amthif callback.
403 *
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200404 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300405 * @cb: callback block.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200406 */
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200407void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200408{
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200409 struct mei_device *dev = cl->dev;
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200410
411 if (cb->fop_type == MEI_FOP_WRITE) {
412 if (!cb->status) {
413 dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
414 mei_io_cb_free(cb);
415 return;
416 }
417 /*
418 * in case of error enqueue the write cb to complete read list
419 * so it can be propagated to the reader
420 */
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200421 list_add_tail(&cb->list, &cl->rd_completed);
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200422 wake_up_interruptible(&dev->iamthif_cl.wait);
423 return;
424 }
425
Alexander Usyskinedf56002015-10-13 15:02:41 +0300426 if (!dev->iamthif_canceled) {
Tomas Winkler19838fb2012-11-01 21:17:15 +0200427 dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
428 dev->iamthif_stall_timer = 0;
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200429 list_add_tail(&cb->list, &cl->rd_completed);
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300430 dev_dbg(dev->dev, "amthif read completed\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200431 } else {
432 mei_amthif_run_next_cmd(dev);
433 }
434
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300435 dev_dbg(dev->dev, "completing amthif call back.\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200436 wake_up_interruptible(&dev->iamthif_cl.wait);
437}
438
Tomas Winklera562d5c2012-11-11 17:38:01 +0200439/**
440 * mei_clear_list - removes all callbacks associated with file
441 * from mei_cb_list
442 *
443 * @dev: device structure.
444 * @file: file structure
445 * @mei_cb_list: callbacks list
446 *
447 * mei_clear_list is called to clear resources associated with file
448 * when application calls close function or Ctrl-C was pressed
449 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300450 * Return: true if callback removed from the list, false otherwise
Tomas Winklera562d5c2012-11-11 17:38:01 +0200451 */
452static bool mei_clear_list(struct mei_device *dev,
453 const struct file *file, struct list_head *mei_cb_list)
454{
Tomas Winkler928fa662015-02-10 10:39:45 +0200455 struct mei_cl *cl = &dev->iamthif_cl;
456 struct mei_cl_cb *cb, *next;
Tomas Winklera562d5c2012-11-11 17:38:01 +0200457 bool removed = false;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200458
Tomas Winklera562d5c2012-11-11 17:38:01 +0200459 /* list all list member */
Tomas Winkler928fa662015-02-10 10:39:45 +0200460 list_for_each_entry_safe(cb, next, mei_cb_list, list) {
Tomas Winklera562d5c2012-11-11 17:38:01 +0200461 /* check if list member associated with a file */
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200462 if (file == cb->fp) {
Tomas Winklera562d5c2012-11-11 17:38:01 +0200463 /* check if cb equal to current iamthif cb */
Tomas Winkler928fa662015-02-10 10:39:45 +0200464 if (dev->iamthif_current_cb == cb) {
Tomas Winklera562d5c2012-11-11 17:38:01 +0200465 dev->iamthif_current_cb = NULL;
466 /* send flow control to iamthif client */
Tomas Winkler928fa662015-02-10 10:39:45 +0200467 mei_hbm_cl_flow_control_req(dev, cl);
Tomas Winklera562d5c2012-11-11 17:38:01 +0200468 }
469 /* free all allocated buffers */
Tomas Winkler928fa662015-02-10 10:39:45 +0200470 mei_io_cb_free(cb);
Tomas Winklera562d5c2012-11-11 17:38:01 +0200471 removed = true;
472 }
473 }
474 return removed;
475}
476
477/**
478 * mei_clear_lists - removes all callbacks associated with file
479 *
480 * @dev: device structure
481 * @file: file structure
482 *
483 * mei_clear_lists is called to clear resources associated with file
484 * when application calls close function or Ctrl-C was pressed
485 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300486 * Return: true if callback removed from the list, false otherwise
Tomas Winklera562d5c2012-11-11 17:38:01 +0200487 */
Tomas Winklerf23e2cc2016-02-07 23:35:23 +0200488static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
Tomas Winklera562d5c2012-11-11 17:38:01 +0200489{
490 bool removed = false;
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200491 struct mei_cl *cl = &dev->iamthif_cl;
Tomas Winklera562d5c2012-11-11 17:38:01 +0200492
493 /* remove callbacks associated with a file */
494 mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
Tomas Winkler9abd8b32016-02-07 23:35:26 +0200495 if (mei_clear_list(dev, file, &cl->rd_completed))
Tomas Winklera562d5c2012-11-11 17:38:01 +0200496 removed = true;
497
498 mei_clear_list(dev, file, &dev->ctrl_rd_list.list);
499
500 if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list))
501 removed = true;
502
503 if (mei_clear_list(dev, file, &dev->write_waiting_list.list))
504 removed = true;
505
506 if (mei_clear_list(dev, file, &dev->write_list.list))
507 removed = true;
508
509 /* check if iamthif_current_cb not NULL */
510 if (dev->iamthif_current_cb && !removed) {
511 /* check file and iamthif current cb association */
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200512 if (dev->iamthif_current_cb->fp == file) {
Tomas Winklera562d5c2012-11-11 17:38:01 +0200513 /* remove cb */
514 mei_io_cb_free(dev->iamthif_current_cb);
515 dev->iamthif_current_cb = NULL;
516 removed = true;
517 }
518 }
519 return removed;
520}
521
522/**
523* mei_amthif_release - the release function
524*
Masanari Iida393b1482013-04-05 01:05:05 +0900525* @dev: device structure
Tomas Winklera562d5c2012-11-11 17:38:01 +0200526* @file: pointer to file structure
527*
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300528* Return: 0 on success, <0 on error
Tomas Winklera562d5c2012-11-11 17:38:01 +0200529*/
530int mei_amthif_release(struct mei_device *dev, struct file *file)
531{
Tomas Winkler22f96a02013-09-16 23:44:47 +0300532 if (dev->iamthif_open_count > 0)
533 dev->iamthif_open_count--;
Tomas Winklera562d5c2012-11-11 17:38:01 +0200534
Tomas Winkler62e8e6a2016-02-07 23:35:24 +0200535 if (dev->iamthif_fp == file &&
Tomas Winklera562d5c2012-11-11 17:38:01 +0200536 dev->iamthif_state != MEI_IAMTHIF_IDLE) {
537
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300538 dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
Tomas Winklera562d5c2012-11-11 17:38:01 +0200539 dev->iamthif_state);
540 dev->iamthif_canceled = true;
541 if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300542 dev_dbg(dev->dev, "run next amthif iamthif cb\n");
Tomas Winklera562d5c2012-11-11 17:38:01 +0200543 mei_amthif_run_next_cmd(dev);
544 }
545 }
546
547 if (mei_clear_lists(dev, file))
548 dev->iamthif_state = MEI_IAMTHIF_IDLE;
549
550 return 0;
551}