blob: 2cc41cb3bb38671ce8717442ef1c38ac8ae2cc9c [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>
22#include <linux/aio.h>
Tomas Winkler19838fb2012-11-01 21:17:15 +020023#include <linux/ioctl.h>
24#include <linux/cdev.h>
25#include <linux/list.h>
26#include <linux/delay.h>
27#include <linux/sched.h>
28#include <linux/uuid.h>
29#include <linux/jiffies.h>
30#include <linux/uaccess.h>
Tomas Winkler1f180352014-09-29 16:31:46 +030031#include <linux/slab.h>
Tomas Winkler19838fb2012-11-01 21:17:15 +020032
Tomas Winkler47a73802012-12-25 19:06:03 +020033#include <linux/mei.h>
Tomas Winkler19838fb2012-11-01 21:17:15 +020034
35#include "mei_dev.h"
Tomas Winkler0edb23f2013-01-08 23:07:12 +020036#include "hbm.h"
Tomas Winkler90e0b5f2013-01-08 23:07:14 +020037#include "client.h"
Tomas Winkler19838fb2012-11-01 21:17:15 +020038
Tomas Winkler1a1aca42013-01-08 23:07:21 +020039const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
40 0xac, 0xa8, 0x46, 0xe0,
41 0xff, 0x65, 0x81, 0x4c);
Tomas Winkler19838fb2012-11-01 21:17:15 +020042
43/**
44 * mei_amthif_reset_params - initializes mei device iamthif
45 *
46 * @dev: the device structure
47 */
48void mei_amthif_reset_params(struct mei_device *dev)
49{
50 /* reset iamthif parameters. */
51 dev->iamthif_current_cb = NULL;
Tomas Winkler19838fb2012-11-01 21:17:15 +020052 dev->iamthif_canceled = false;
Tomas Winkler19838fb2012-11-01 21:17:15 +020053 dev->iamthif_state = MEI_IAMTHIF_IDLE;
54 dev->iamthif_timer = 0;
Alexander Usyskin4a704572013-09-02 13:29:47 +030055 dev->iamthif_stall_timer = 0;
Tomas Winkler22f96a02013-09-16 23:44:47 +030056 dev->iamthif_open_count = 0;
Tomas Winkler19838fb2012-11-01 21:17:15 +020057}
58
59/**
Masanari Iida393b1482013-04-05 01:05:05 +090060 * mei_amthif_host_init - mei initialization amthif client.
Tomas Winkler19838fb2012-11-01 21:17:15 +020061 *
62 * @dev: the device structure
63 *
Alexander Usyskince231392014-09-29 16:31:50 +030064 * Return: 0 on success, <0 on failure.
Tomas Winkler19838fb2012-11-01 21:17:15 +020065 */
Tomas Winkler781d0d82013-01-08 23:07:22 +020066int mei_amthif_host_init(struct mei_device *dev)
Tomas Winkler19838fb2012-11-01 21:17:15 +020067{
Tomas Winkler781d0d82013-01-08 23:07:22 +020068 struct mei_cl *cl = &dev->iamthif_cl;
Tomas Winklerd3208322014-08-24 12:08:55 +030069 struct mei_me_client *me_cl;
Tomas Winklerd3208322014-08-24 12:08:55 +030070 int ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +020071
Tomas Winkler6222f7b2013-01-08 23:07:23 +020072 dev->iamthif_state = MEI_IAMTHIF_IDLE;
73
Tomas Winkler781d0d82013-01-08 23:07:22 +020074 mei_cl_init(cl, dev);
Tomas Winkler19838fb2012-11-01 21:17:15 +020075
Tomas Winklerd3208322014-08-24 12:08:55 +030076 me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
77 if (!me_cl) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +030078 dev_info(dev->dev, "amthif: failed to find the client");
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +020079 return -ENOTTY;
Tomas Winkler19838fb2012-11-01 21:17:15 +020080 }
81
Tomas Winklerd3208322014-08-24 12:08:55 +030082 cl->me_client_id = me_cl->client_id;
Tomas Winklerd880f322014-08-21 14:29:15 +030083 cl->cl_uuid = me_cl->props.protocol_name;
Tomas Winkler781d0d82013-01-08 23:07:22 +020084
Tomas Winkler19838fb2012-11-01 21:17:15 +020085 /* Assign iamthif_mtu to the value received from ME */
86
Tomas Winklerd3208322014-08-24 12:08:55 +030087 dev->iamthif_mtu = me_cl->props.max_msg_length;
Tomas Winkler2bf94cab2014-09-29 16:31:42 +030088 dev_dbg(dev->dev, "IAMTHIF_MTU = %d\n", dev->iamthif_mtu);
Tomas Winkler19838fb2012-11-01 21:17:15 +020089
Tomas Winkler19838fb2012-11-01 21:17:15 +020090
Tomas Winkler781d0d82013-01-08 23:07:22 +020091 ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
Tomas Winkler781d0d82013-01-08 23:07:22 +020092 if (ret < 0) {
Tomas Winkler79563db2015-01-11 00:07:16 +020093 dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
94 goto out;
Tomas Winkler19838fb2012-11-01 21:17:15 +020095 }
Tomas Winkler781d0d82013-01-08 23:07:22 +020096
Tomas Winkler64092852014-02-17 15:13:21 +020097 ret = mei_cl_connect(cl, NULL);
98
99 dev->iamthif_state = MEI_IAMTHIF_IDLE;
100
Tomas Winkler79563db2015-01-11 00:07:16 +0200101out:
102 mei_me_cl_put(me_cl);
Tomas Winkler64092852014-02-17 15:13:21 +0200103 return ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200104}
105
106/**
107 * mei_amthif_find_read_list_entry - finds a amthilist entry for current file
108 *
109 * @dev: the device structure
110 * @file: pointer to file object
111 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300112 * Return: returned a list entry on success, NULL on failure.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200113 */
114struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
115 struct file *file)
116{
Tomas Winkler31f88f52014-02-17 15:13:25 +0200117 struct mei_cl_cb *cb;
Tomas Winkler92db1552014-09-29 16:31:37 +0300118
Alexander Usyskin05e314e2014-08-14 17:22:21 +0300119 list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
120 if (cb->file_object == file)
Tomas Winkler31f88f52014-02-17 15:13:25 +0200121 return cb;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200122 return NULL;
123}
124
125
126/**
127 * mei_amthif_read - read data from AMTHIF client
128 *
129 * @dev: the device structure
Tomas Winkler19838fb2012-11-01 21:17:15 +0200130 * @file: pointer to file object
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300131 * @ubuf: pointer to user data in user space
Tomas Winkler19838fb2012-11-01 21:17:15 +0200132 * @length: data length to read
133 * @offset: data read offset
134 *
135 * Locking: called under "dev->device_lock" lock
136 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300137 * Return:
Tomas Winkler19838fb2012-11-01 21:17:15 +0200138 * returned data length on success,
139 * zero if no data to read,
140 * negative on failure.
141 */
142int mei_amthif_read(struct mei_device *dev, struct file *file,
143 char __user *ubuf, size_t length, loff_t *offset)
144{
Tomas Winklerd3208322014-08-24 12:08:55 +0300145 struct mei_cl *cl = file->private_data;
146 struct mei_cl_cb *cb;
147 unsigned long timeout;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200148 int rets;
149 int wait_ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200150
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200151 /* Only possible if we are in timeout */
Alexander Usyskin05e314e2014-08-14 17:22:21 +0300152 if (!cl) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300153 dev_err(dev->dev, "bad file ext.\n");
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +0200154 return -ETIME;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200155 }
156
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300157 dev_dbg(dev->dev, "checking amthif data\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200158 cb = mei_amthif_find_read_list_entry(dev, file);
159
160 /* Check for if we can block or not*/
161 if (cb == NULL && file->f_flags & O_NONBLOCK)
162 return -EAGAIN;
163
164
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300165 dev_dbg(dev->dev, "waiting for amthif data\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200166 while (cb == NULL) {
167 /* unlock the Mutex */
168 mutex_unlock(&dev->device_lock);
169
170 wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
171 (cb = mei_amthif_find_read_list_entry(dev, file)));
172
Alexey Khoroshilove6028db2012-12-22 01:44:16 +0400173 /* Locking again the Mutex */
174 mutex_lock(&dev->device_lock);
175
Tomas Winkler19838fb2012-11-01 21:17:15 +0200176 if (wait_ret)
177 return -ERESTARTSYS;
178
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300179 dev_dbg(dev->dev, "woke up from sleep\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200180 }
181
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200182 if (cb->status) {
183 rets = cb->status;
184 dev_dbg(dev->dev, "read operation failed %d\n", rets);
185 goto free;
186 }
Tomas Winkler19838fb2012-11-01 21:17:15 +0200187
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300188 dev_dbg(dev->dev, "Got amthif data\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200189 dev->iamthif_timer = 0;
190
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200191 timeout = cb->read_time +
192 mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
193 dev_dbg(dev->dev, "amthif timeout = %lud\n",
194 timeout);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200195
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200196 if (time_after(jiffies, timeout)) {
197 dev_dbg(dev->dev, "amthif Time out\n");
198 /* 15 sec for the message has expired */
199 list_del(&cb->list);
200 rets = -ETIME;
201 goto free;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200202 }
203 /* if the whole message will fit remove it from the list */
204 if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
205 list_del(&cb->list);
206 else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
207 /* end of the message has been reached */
208 list_del(&cb->list);
209 rets = 0;
210 goto free;
211 }
212 /* else means that not full buffer will be read and do not
213 * remove message from deletion list
214 */
215
Tomas Winkler5db75142015-02-10 10:39:42 +0200216 dev_dbg(dev->dev, "amthif cb->buf size - %d\n",
217 cb->buf.size);
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300218 dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200219
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200220 /* length is being truncated to PAGE_SIZE, however,
Tomas Winkler19838fb2012-11-01 21:17:15 +0200221 * the buf_idx may point beyond */
222 length = min_t(size_t, length, (cb->buf_idx - *offset));
223
Tomas Winkler5db75142015-02-10 10:39:42 +0200224 if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300225 dev_dbg(dev->dev, "failed to copy data to userland\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200226 rets = -EFAULT;
Tomas Winkler34e267d2014-03-16 14:35:57 +0200227 } else {
Tomas Winkler19838fb2012-11-01 21:17:15 +0200228 rets = length;
229 if ((*offset + length) < cb->buf_idx) {
230 *offset += length;
231 goto out;
232 }
233 }
234free:
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300235 dev_dbg(dev->dev, "free amthif cb memory.\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200236 *offset = 0;
237 mei_io_cb_free(cb);
238out:
239 return rets;
240}
241
242/**
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200243 * mei_amthif_read_start - queue message for sending read credential
244 *
245 * @cl: host client
246 * @file: file pointer of message recipient
247 *
248 * Return: 0 on success, <0 on failure.
249 */
250static int mei_amthif_read_start(struct mei_cl *cl, struct file *file)
251{
252 struct mei_device *dev = cl->dev;
253 struct mei_cl_cb *cb;
254 size_t length = dev->iamthif_mtu;
255 int rets;
256
257 cb = mei_io_cb_init(cl, file);
258 if (!cb) {
259 rets = -ENOMEM;
260 goto err;
261 }
262
Tomas Winkler5db75142015-02-10 10:39:42 +0200263 rets = mei_io_cb_alloc_buf(cb, length);
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200264 if (rets)
265 goto err;
266
267 cb->fop_type = MEI_FOP_READ;
268 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
269
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200270 dev->iamthif_state = MEI_IAMTHIF_READING;
271 dev->iamthif_file_object = cb->file_object;
272 dev->iamthif_current_cb = cb;
273
274 return 0;
275err:
276 mei_io_cb_free(cb);
277 return rets;
278}
279
280/**
Tomas Winklerab5c4a52012-11-01 21:17:18 +0200281 * mei_amthif_send_cmd - send amthif command to the ME
Tomas Winkler19838fb2012-11-01 21:17:15 +0200282 *
Tomas Winkler86601722015-02-10 10:39:40 +0200283 * @cl: the host client
Tomas Winkler19838fb2012-11-01 21:17:15 +0200284 * @cb: mei call back struct
285 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300286 * Return: 0 on success, <0 on failure.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200287 */
Tomas Winkler86601722015-02-10 10:39:40 +0200288static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200289{
Tomas Winkler86601722015-02-10 10:39:40 +0200290 struct mei_device *dev;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200291 int ret;
292
Tomas Winkler86601722015-02-10 10:39:40 +0200293 if (!cl->dev || !cb)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200294 return -ENODEV;
295
Tomas Winkler86601722015-02-10 10:39:40 +0200296 dev = cl->dev;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200297
298 dev->iamthif_state = MEI_IAMTHIF_WRITING;
299 dev->iamthif_current_cb = cb;
300 dev->iamthif_file_object = cb->file_object;
301 dev->iamthif_canceled = false;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200302
Tomas Winkler86601722015-02-10 10:39:40 +0200303 ret = mei_cl_write(cl, cb, false);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200304 if (ret < 0)
305 return ret;
306
Tomas Winkler86601722015-02-10 10:39:40 +0200307 if (cb->completed)
308 cb->status = mei_amthif_read_start(cl, cb->file_object);
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200309
Tomas Winkler19838fb2012-11-01 21:17:15 +0200310 return 0;
311}
312
313/**
Alexander Usyskince231392014-09-29 16:31:50 +0300314 * mei_amthif_run_next_cmd - send next amt command from queue
Tomas Winkler19838fb2012-11-01 21:17:15 +0200315 *
316 * @dev: the device structure
Tomas Winkler86601722015-02-10 10:39:40 +0200317 *
318 * Return: 0 on success, <0 on failure.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200319 */
Tomas Winkler86601722015-02-10 10:39:40 +0200320int mei_amthif_run_next_cmd(struct mei_device *dev)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200321{
Tomas Winkler86601722015-02-10 10:39:40 +0200322 struct mei_cl *cl = &dev->iamthif_cl;
Alexander Usyskin05e314e2014-08-14 17:22:21 +0300323 struct mei_cl_cb *cb;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200324
Tomas Winkler19838fb2012-11-01 21:17:15 +0200325 dev->iamthif_canceled = false;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200326 dev->iamthif_state = MEI_IAMTHIF_IDLE;
327 dev->iamthif_timer = 0;
328 dev->iamthif_file_object = NULL;
329
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300330 dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200331
Alexander Usyskin140c7552014-10-02 13:39:31 +0300332 cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
333 typeof(*cb), list);
334 if (!cb)
Tomas Winkler86601722015-02-10 10:39:40 +0200335 return 0;
336
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200337 list_del_init(&cb->list);
Tomas Winkler86601722015-02-10 10:39:40 +0200338 return mei_amthif_send_cmd(cl, cb);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200339}
340
Tomas Winkler86601722015-02-10 10:39:40 +0200341/**
342 * mei_amthif_write - write amthif data to amthif client
343 *
344 * @cl: host client
345 * @cb: mei call back struct
346 *
347 * Return: 0 on success, <0 on failure.
348 */
349int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
350{
351
352 struct mei_device *dev;
353
354 if (WARN_ON(!cl || !cl->dev))
355 return -ENODEV;
356
357 if (WARN_ON(!cb))
358 return -EINVAL;
359
360 dev = cl->dev;
361
362 cb->fop_type = MEI_FOP_WRITE;
363 list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
364 return mei_amthif_run_next_cmd(dev);
365}
Tomas Winkler744f0f22012-11-11 17:38:02 +0200366
367unsigned int mei_amthif_poll(struct mei_device *dev,
368 struct file *file, poll_table *wait)
369{
370 unsigned int mask = 0;
Tomas Winklerb950ac12013-07-25 20:15:53 +0300371
Tomas Winkler744f0f22012-11-11 17:38:02 +0200372 poll_wait(file, &dev->iamthif_cl.wait, wait);
Tomas Winklerb950ac12013-07-25 20:15:53 +0300373
Tomas Winkler744f0f22012-11-11 17:38:02 +0200374 mutex_lock(&dev->device_lock);
Tomas Winklerb950ac12013-07-25 20:15:53 +0300375 if (!mei_cl_is_connected(&dev->iamthif_cl)) {
376
377 mask = POLLERR;
378
379 } else if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
380 dev->iamthif_file_object == file) {
381
Tomas Winkler744f0f22012-11-11 17:38:02 +0200382 mask |= (POLLIN | POLLRDNORM);
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300383 dev_dbg(dev->dev, "run next amthif cb\n");
Tomas Winkler744f0f22012-11-11 17:38:02 +0200384 mei_amthif_run_next_cmd(dev);
385 }
Tomas Winklerb950ac12013-07-25 20:15:53 +0300386 mutex_unlock(&dev->device_lock);
387
Tomas Winkler744f0f22012-11-11 17:38:02 +0200388 return mask;
389}
390
391
392
Tomas Winkler19838fb2012-11-01 21:17:15 +0200393/**
Tomas Winkler9d098192014-02-19 17:35:48 +0200394 * mei_amthif_irq_write - write iamthif command in irq thread context.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200395 *
Tomas Winkler19838fb2012-11-01 21:17:15 +0200396 * @cl: private data of the file object.
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300397 * @cb: callback block.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200398 * @cmpl_list: complete list.
399 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300400 * Return: 0, OK; otherwise, error.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200401 */
Tomas Winkler9d098192014-02-19 17:35:48 +0200402int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
403 struct mei_cl_cb *cmpl_list)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200404{
Tomas Winkler86601722015-02-10 10:39:40 +0200405 int ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200406
Tomas Winkler86601722015-02-10 10:39:40 +0200407 ret = mei_cl_irq_write(cl, cb, cmpl_list);
408 if (ret)
409 return ret;
Tomas Winkler136698e2013-09-16 23:44:44 +0300410
Tomas Winkler86601722015-02-10 10:39:40 +0200411 if (cb->completed)
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200412 cb->status = mei_amthif_read_start(cl, cb->file_object);
Tomas Winkler24c656e2012-11-18 15:13:17 +0200413
Tomas Winkler19838fb2012-11-01 21:17:15 +0200414 return 0;
415}
416
417/**
Alexander Usyskince231392014-09-29 16:31:50 +0300418 * mei_amthif_irq_read_msg - read routine after ISR to
Tomas Winkler1a1aca42013-01-08 23:07:21 +0200419 * handle the read amthif message
Tomas Winkler19838fb2012-11-01 21:17:15 +0200420 *
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200421 * @cl: mei client
Tomas Winkler1a1aca42013-01-08 23:07:21 +0200422 * @mei_hdr: header of amthif message
Tomas Winkler331e4182015-02-10 10:39:41 +0200423 * @cmpl_list: completed callbacks list
Tomas Winkler19838fb2012-11-01 21:17:15 +0200424 *
Tomas Winkler331e4182015-02-10 10:39:41 +0200425 * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
Tomas Winkler19838fb2012-11-01 21:17:15 +0200426 */
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200427int mei_amthif_irq_read_msg(struct mei_cl *cl,
Tomas Winkler5ceb46e2013-04-19 21:16:53 +0300428 struct mei_msg_hdr *mei_hdr,
Tomas Winkler331e4182015-02-10 10:39:41 +0200429 struct mei_cl_cb *cmpl_list)
Tomas Winkler19838fb2012-11-01 21:17:15 +0200430{
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200431 struct mei_device *dev;
Tomas Winkler331e4182015-02-10 10:39:41 +0200432 int ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200433
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200434 dev = cl->dev;
435
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200436 if (dev->iamthif_state != MEI_IAMTHIF_READING)
Tomas Winkler331e4182015-02-10 10:39:41 +0200437 return 0;
Tomas Winklerdb4756f2015-02-10 10:39:37 +0200438
Tomas Winkler331e4182015-02-10 10:39:41 +0200439 ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
440 if (ret)
441 return ret;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200442
443 if (!mei_hdr->msg_complete)
444 return 0;
445
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300446 dev_dbg(dev->dev, "completed amthif read.\n ");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200447 dev->iamthif_current_cb = NULL;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200448 dev->iamthif_stall_timer = 0;
Tomas Winkler4e097bc2015-02-10 10:39:38 +0200449
Tomas Winkler19838fb2012-11-01 21:17:15 +0200450 return 0;
451}
452
453/**
454 * mei_amthif_complete - complete amthif callback.
455 *
456 * @dev: the device structure.
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300457 * @cb: callback block.
Tomas Winkler19838fb2012-11-01 21:17:15 +0200458 */
459void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
460{
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200461
462 if (cb->fop_type == MEI_FOP_WRITE) {
463 if (!cb->status) {
464 dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
465 mei_io_cb_free(cb);
466 return;
467 }
468 /*
469 * in case of error enqueue the write cb to complete read list
470 * so it can be propagated to the reader
471 */
472 list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
473 wake_up_interruptible(&dev->iamthif_cl.wait);
474 return;
475 }
476
Tomas Winkler19838fb2012-11-01 21:17:15 +0200477 if (dev->iamthif_canceled != 1) {
478 dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
479 dev->iamthif_stall_timer = 0;
Tomas Winklere773efc2012-11-11 17:37:58 +0200480 list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300481 dev_dbg(dev->dev, "amthif read completed\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200482 dev->iamthif_timer = jiffies;
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300483 dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
Tomas Winklerc54bf3a2015-02-10 10:39:39 +0200484 dev->iamthif_timer);
Tomas Winkler19838fb2012-11-01 21:17:15 +0200485 } else {
486 mei_amthif_run_next_cmd(dev);
487 }
488
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300489 dev_dbg(dev->dev, "completing amthif call back.\n");
Tomas Winkler19838fb2012-11-01 21:17:15 +0200490 wake_up_interruptible(&dev->iamthif_cl.wait);
491}
492
Tomas Winklera562d5c2012-11-11 17:38:01 +0200493/**
494 * mei_clear_list - removes all callbacks associated with file
495 * from mei_cb_list
496 *
497 * @dev: device structure.
498 * @file: file structure
499 * @mei_cb_list: callbacks list
500 *
501 * mei_clear_list is called to clear resources associated with file
502 * when application calls close function or Ctrl-C was pressed
503 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300504 * Return: true if callback removed from the list, false otherwise
Tomas Winklera562d5c2012-11-11 17:38:01 +0200505 */
506static bool mei_clear_list(struct mei_device *dev,
507 const struct file *file, struct list_head *mei_cb_list)
508{
509 struct mei_cl_cb *cb_pos = NULL;
510 struct mei_cl_cb *cb_next = NULL;
511 bool removed = false;
Tomas Winkler19838fb2012-11-01 21:17:15 +0200512
Tomas Winklera562d5c2012-11-11 17:38:01 +0200513 /* list all list member */
514 list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) {
515 /* check if list member associated with a file */
516 if (file == cb_pos->file_object) {
517 /* remove member from the list */
518 list_del(&cb_pos->list);
519 /* check if cb equal to current iamthif cb */
520 if (dev->iamthif_current_cb == cb_pos) {
521 dev->iamthif_current_cb = NULL;
522 /* send flow control to iamthif client */
Tomas Winkler8120e722012-12-25 19:06:11 +0200523 mei_hbm_cl_flow_control_req(dev,
524 &dev->iamthif_cl);
Tomas Winklera562d5c2012-11-11 17:38:01 +0200525 }
526 /* free all allocated buffers */
527 mei_io_cb_free(cb_pos);
528 cb_pos = NULL;
529 removed = true;
530 }
531 }
532 return removed;
533}
534
535/**
536 * mei_clear_lists - removes all callbacks associated with file
537 *
538 * @dev: device structure
539 * @file: file structure
540 *
541 * mei_clear_lists is called to clear resources associated with file
542 * when application calls close function or Ctrl-C was pressed
543 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300544 * Return: true if callback removed from the list, false otherwise
Tomas Winklera562d5c2012-11-11 17:38:01 +0200545 */
546static bool mei_clear_lists(struct mei_device *dev, struct file *file)
547{
548 bool removed = false;
549
550 /* remove callbacks associated with a file */
551 mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
552 if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list))
553 removed = true;
554
555 mei_clear_list(dev, file, &dev->ctrl_rd_list.list);
556
557 if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list))
558 removed = true;
559
560 if (mei_clear_list(dev, file, &dev->write_waiting_list.list))
561 removed = true;
562
563 if (mei_clear_list(dev, file, &dev->write_list.list))
564 removed = true;
565
566 /* check if iamthif_current_cb not NULL */
567 if (dev->iamthif_current_cb && !removed) {
568 /* check file and iamthif current cb association */
569 if (dev->iamthif_current_cb->file_object == file) {
570 /* remove cb */
571 mei_io_cb_free(dev->iamthif_current_cb);
572 dev->iamthif_current_cb = NULL;
573 removed = true;
574 }
575 }
576 return removed;
577}
578
579/**
580* mei_amthif_release - the release function
581*
Masanari Iida393b1482013-04-05 01:05:05 +0900582* @dev: device structure
Tomas Winklera562d5c2012-11-11 17:38:01 +0200583* @file: pointer to file structure
584*
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300585* Return: 0 on success, <0 on error
Tomas Winklera562d5c2012-11-11 17:38:01 +0200586*/
587int mei_amthif_release(struct mei_device *dev, struct file *file)
588{
Tomas Winkler22f96a02013-09-16 23:44:47 +0300589 if (dev->iamthif_open_count > 0)
590 dev->iamthif_open_count--;
Tomas Winklera562d5c2012-11-11 17:38:01 +0200591
592 if (dev->iamthif_file_object == file &&
593 dev->iamthif_state != MEI_IAMTHIF_IDLE) {
594
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300595 dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
Tomas Winklera562d5c2012-11-11 17:38:01 +0200596 dev->iamthif_state);
597 dev->iamthif_canceled = true;
598 if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300599 dev_dbg(dev->dev, "run next amthif iamthif cb\n");
Tomas Winklera562d5c2012-11-11 17:38:01 +0200600 mei_amthif_run_next_cmd(dev);
601 }
602 }
603
604 if (mei_clear_lists(dev, file))
605 dev->iamthif_state = MEI_IAMTHIF_IDLE;
606
607 return 0;
608}