blob: 2891bc44f9d49764ed98e328ccc0511bc340160c [file] [log] [blame]
Oren Weilab841162011-05-15 13:43:41 +03001/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
Tomas Winkler733ba912012-02-09 19:25:53 +02004 * Copyright (c) 2003-2012, Intel Corporation.
Oren Weilab841162011-05-15 13:43:41 +03005 *
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
18#include <linux/kernel.h>
19#include <linux/fs.h>
20#include <linux/errno.h>
21#include <linux/types.h>
22#include <linux/fcntl.h>
23#include <linux/aio.h>
24#include <linux/pci.h>
25#include <linux/init.h>
26#include <linux/ioctl.h>
27#include <linux/cdev.h>
28#include <linux/list.h>
29#include <linux/delay.h>
30#include <linux/sched.h>
31#include <linux/uuid.h>
32#include <linux/jiffies.h>
33#include <linux/uaccess.h>
34
35
36#include "mei_dev.h"
37#include "hw.h"
Tomas Winkler4f3afe12012-05-09 16:38:59 +030038#include <linux/mei.h>
Oren Weilab841162011-05-15 13:43:41 +030039#include "interface.h"
Oren Weilab841162011-05-15 13:43:41 +030040
Tomas Winkler07b509b2012-07-23 14:05:39 +030041/**
Tomas Winkler601a1ef2012-10-09 16:50:20 +020042 * mei_io_cb_free - free mei_cb_private related memory
43 *
44 * @cb: mei callback struct
45 */
46void mei_io_cb_free(struct mei_cl_cb *cb)
47{
48 if (cb == NULL)
49 return;
50
51 kfree(cb->request_buffer.data);
52 kfree(cb->response_buffer.data);
53 kfree(cb);
54}
55
56/**
Tomas Winkler07b509b2012-07-23 14:05:39 +030057 * mei_me_cl_by_id return index to me_clients for client_id
58 *
59 * @dev: the device structure
60 * @client_id: me client id
61 *
62 * Locking: called under "dev->device_lock" lock
63 *
64 * returns index on success, -ENOENT on failure.
65 */
Oren Weilab841162011-05-15 13:43:41 +030066
Tomas Winkler07b509b2012-07-23 14:05:39 +030067int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
68{
69 int i;
70 for (i = 0; i < dev->me_clients_num; i++)
71 if (dev->me_clients[i].client_id == client_id)
72 break;
73 if (WARN_ON(dev->me_clients[i].client_id != client_id))
74 return -ENOENT;
75
76 if (i == dev->me_clients_num)
77 return -ENOENT;
78
79 return i;
80}
Oren Weilab841162011-05-15 13:43:41 +030081
82/**
83 * mei_ioctl_connect_client - the connect to fw client IOCTL function
84 *
85 * @dev: the device structure
86 * @data: IOCTL connect data, input and output parameters
87 * @file: private data of the file object
88 *
89 * Locking: called under "dev->device_lock" lock
90 *
91 * returns 0 on success, <0 on failure.
92 */
93int mei_ioctl_connect_client(struct file *file,
94 struct mei_connect_client_data *data)
95{
96 struct mei_device *dev;
97 struct mei_cl_cb *cb;
98 struct mei_client *client;
99 struct mei_cl *cl;
100 struct mei_cl *cl_pos = NULL;
101 struct mei_cl *cl_next = NULL;
102 long timeout = CONNECT_TIMEOUT;
103 int i;
104 int err;
105 int rets;
106
107 cl = file->private_data;
108 if (WARN_ON(!cl || !cl->dev))
109 return -ENODEV;
110
111 dev = cl->dev;
112
113 dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
114
115
116 /* buffered ioctl cb */
117 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
118 if (!cb) {
119 rets = -ENOMEM;
120 goto end;
121 }
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200122 mei_io_list_init(cb);
Oren Weilab841162011-05-15 13:43:41 +0300123
124 cb->major_file_operations = MEI_IOCTL;
125
Tomas Winklerb210d752012-08-07 00:03:56 +0300126 if (dev->dev_state != MEI_DEV_ENABLED) {
Oren Weilab841162011-05-15 13:43:41 +0300127 rets = -ENODEV;
128 goto end;
129 }
130 if (cl->state != MEI_FILE_INITIALIZING &&
131 cl->state != MEI_FILE_DISCONNECTED) {
132 rets = -EBUSY;
133 goto end;
134 }
135
136 /* find ME client we're trying to connect to */
Tomas Winkler07b509b2012-07-23 14:05:39 +0300137 i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
Oren Weilab841162011-05-15 13:43:41 +0300138 if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
139 cl->me_client_id = dev->me_clients[i].client_id;
140 cl->state = MEI_FILE_CONNECTING;
141 }
142
143 dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
144 cl->me_client_id);
145 dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
146 dev->me_clients[i].props.protocol_version);
147 dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
148 dev->me_clients[i].props.max_msg_length);
149
Justin P. Mattock5f9092f2012-03-12 07:18:09 -0700150 /* if we're connecting to amthi client then we will use the
151 * existing connection
Oren Weilab841162011-05-15 13:43:41 +0300152 */
153 if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
154 dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
155 if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
156 rets = -ENODEV;
157 goto end;
158 }
159 clear_bit(cl->host_client_id, dev->host_clients_map);
160 list_for_each_entry_safe(cl_pos, cl_next,
161 &dev->file_list, link) {
Tomas Winkler0288c7c2011-06-06 10:44:34 +0300162 if (mei_cl_cmp_id(cl, cl_pos)) {
Oren Weilab841162011-05-15 13:43:41 +0300163 dev_dbg(&dev->pdev->dev,
164 "remove file private data node host"
165 " client = %d, ME client = %d.\n",
166 cl_pos->host_client_id,
167 cl_pos->me_client_id);
168 list_del(&cl_pos->link);
169 }
170
171 }
172 dev_dbg(&dev->pdev->dev, "free file private data memory.\n");
173 kfree(cl);
174
175 cl = NULL;
176 file->private_data = &dev->iamthif_cl;
177
178 client = &data->out_client_properties;
179 client->max_msg_length =
180 dev->me_clients[i].props.max_msg_length;
181 client->protocol_version =
182 dev->me_clients[i].props.protocol_version;
183 rets = dev->iamthif_cl.status;
184
185 goto end;
186 }
187
188 if (cl->state != MEI_FILE_CONNECTING) {
189 rets = -ENODEV;
190 goto end;
191 }
192
193
194 /* prepare the output buffer */
195 client = &data->out_client_properties;
196 client->max_msg_length = dev->me_clients[i].props.max_msg_length;
197 client->protocol_version = dev->me_clients[i].props.protocol_version;
198 dev_dbg(&dev->pdev->dev, "Can connect?\n");
199 if (dev->mei_host_buffer_is_empty
200 && !mei_other_client_is_connecting(dev, cl)) {
201 dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300202 dev->mei_host_buffer_is_empty = false;
Tomas Winkler1ccb7b62012-03-14 14:39:42 +0200203 if (mei_connect(dev, cl)) {
Oren Weilab841162011-05-15 13:43:41 +0300204 dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
205 rets = -ENODEV;
206 goto end;
207 } else {
208 dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
209 cl->timer_count = MEI_CONNECT_TIMEOUT;
210 cb->file_private = cl;
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200211 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300212 }
213
214
215 } else {
216 dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
217 cb->file_private = cl;
218 dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200219 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300220 }
221 mutex_unlock(&dev->device_lock);
222 err = wait_event_timeout(dev->wait_recvd_msg,
223 (MEI_FILE_CONNECTED == cl->state ||
224 MEI_FILE_DISCONNECTED == cl->state),
225 timeout * HZ);
226
227 mutex_lock(&dev->device_lock);
228 if (MEI_FILE_CONNECTED == cl->state) {
229 dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
230 rets = cl->status;
231 goto end;
232 } else {
233 dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
234 cl->state);
235 if (!err) {
236 dev_dbg(&dev->pdev->dev,
237 "wait_event_interruptible_timeout failed on client"
238 " connect message fw response message.\n");
239 }
240 rets = -EFAULT;
241
Tomas Winkler0288c7c2011-06-06 10:44:34 +0300242 mei_io_list_flush(&dev->ctrl_rd_list, cl);
243 mei_io_list_flush(&dev->ctrl_wr_list, cl);
Oren Weilab841162011-05-15 13:43:41 +0300244 goto end;
245 }
246 rets = 0;
247end:
248 dev_dbg(&dev->pdev->dev, "free connect cb memory.");
Tomas Winkler601a1ef2012-10-09 16:50:20 +0200249 mei_io_cb_free(cb);
Oren Weilab841162011-05-15 13:43:41 +0300250 return rets;
251}
252
253/**
254 * find_amthi_read_list_entry - finds a amthilist entry for current file
255 *
256 * @dev: the device structure
257 * @file: pointer to file object
258 *
259 * returns returned a list entry on success, NULL on failure.
260 */
261struct mei_cl_cb *find_amthi_read_list_entry(
262 struct mei_device *dev,
263 struct file *file)
264{
265 struct mei_cl *cl_temp;
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200266 struct mei_cl_cb *pos = NULL;
267 struct mei_cl_cb *next = NULL;
Oren Weilab841162011-05-15 13:43:41 +0300268
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200269 list_for_each_entry_safe(pos, next,
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200270 &dev->amthi_read_complete_list.list, list) {
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200271 cl_temp = (struct mei_cl *)pos->file_private;
272 if (cl_temp && cl_temp == &dev->iamthif_cl &&
273 pos->file_object == file)
274 return pos;
Oren Weilab841162011-05-15 13:43:41 +0300275 }
276 return NULL;
277}
278
279/**
280 * amthi_read - read data from AMTHI client
281 *
282 * @dev: the device structure
283 * @if_num: minor number
284 * @file: pointer to file object
285 * @*ubuf: pointer to user data in user space
286 * @length: data length to read
287 * @offset: data read offset
288 *
289 * Locking: called under "dev->device_lock" lock
290 *
291 * returns
292 * returned data length on success,
293 * zero if no data to read,
294 * negative on failure.
295 */
296int amthi_read(struct mei_device *dev, struct file *file,
Tomas Winkler441ab502011-12-13 23:39:34 +0200297 char __user *ubuf, size_t length, loff_t *offset)
Oren Weilab841162011-05-15 13:43:41 +0300298{
299 int rets;
300 int wait_ret;
301 struct mei_cl_cb *cb = NULL;
302 struct mei_cl *cl = file->private_data;
303 unsigned long timeout;
304 int i;
305
306 /* Only Posible if we are in timeout */
307 if (!cl || cl != &dev->iamthif_cl) {
308 dev_dbg(&dev->pdev->dev, "bad file ext.\n");
309 return -ETIMEDOUT;
310 }
311
Tomas Winkler07b509b2012-07-23 14:05:39 +0300312 i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
Oren Weilab841162011-05-15 13:43:41 +0300313
Tomas Winkler07b509b2012-07-23 14:05:39 +0300314 if (i < 0) {
Oren Weilab841162011-05-15 13:43:41 +0300315 dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
316 return -ENODEV;
317 }
Oren Weilab841162011-05-15 13:43:41 +0300318 dev_dbg(&dev->pdev->dev, "checking amthi data\n");
319 cb = find_amthi_read_list_entry(dev, file);
320
321 /* Check for if we can block or not*/
322 if (cb == NULL && file->f_flags & O_NONBLOCK)
323 return -EAGAIN;
324
325
326 dev_dbg(&dev->pdev->dev, "waiting for amthi data\n");
327 while (cb == NULL) {
328 /* unlock the Mutex */
329 mutex_unlock(&dev->device_lock);
330
331 wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
332 (cb = find_amthi_read_list_entry(dev, file)));
333
334 if (wait_ret)
335 return -ERESTARTSYS;
336
337 dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
338
339 /* Locking again the Mutex */
340 mutex_lock(&dev->device_lock);
341 }
342
343
344 dev_dbg(&dev->pdev->dev, "Got amthi data\n");
345 dev->iamthif_timer = 0;
346
347 if (cb) {
Tomas Winkler07b509b2012-07-23 14:05:39 +0300348 timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER);
Oren Weilab841162011-05-15 13:43:41 +0300349 dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
350 timeout);
351
352 if (time_after(jiffies, timeout)) {
353 dev_dbg(&dev->pdev->dev, "amthi Time out\n");
354 /* 15 sec for the message has expired */
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200355 list_del(&cb->list);
Oren Weilab841162011-05-15 13:43:41 +0300356 rets = -ETIMEDOUT;
357 goto free;
358 }
359 }
360 /* if the whole message will fit remove it from the list */
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200361 if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200362 list_del(&cb->list);
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200363 else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
Oren Weilab841162011-05-15 13:43:41 +0300364 /* end of the message has been reached */
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200365 list_del(&cb->list);
Oren Weilab841162011-05-15 13:43:41 +0300366 rets = 0;
367 goto free;
368 }
369 /* else means that not full buffer will be read and do not
370 * remove message from deletion list
371 */
372
373 dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n",
374 cb->response_buffer.size);
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200375 dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx);
Oren Weilab841162011-05-15 13:43:41 +0300376
377 /* length is being turncated to PAGE_SIZE, however,
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200378 * the buf_idx may point beyond */
379 length = min_t(size_t, length, (cb->buf_idx - *offset));
Oren Weilab841162011-05-15 13:43:41 +0300380
Tomas Winkler441ab502011-12-13 23:39:34 +0200381 if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
Oren Weilab841162011-05-15 13:43:41 +0300382 rets = -EFAULT;
383 else {
384 rets = length;
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200385 if ((*offset + length) < cb->buf_idx) {
Oren Weilab841162011-05-15 13:43:41 +0300386 *offset += length;
387 goto out;
388 }
389 }
390free:
391 dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n");
392 *offset = 0;
Tomas Winkler601a1ef2012-10-09 16:50:20 +0200393 mei_io_cb_free(cb);
Oren Weilab841162011-05-15 13:43:41 +0300394out:
395 return rets;
396}
397
398/**
399 * mei_start_read - the start read client message function.
400 *
401 * @dev: the device structure
402 * @if_num: minor number
403 * @cl: private data of the file object
404 *
405 * returns 0 on success, <0 on failure.
406 */
407int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
408{
409 struct mei_cl_cb *cb;
410 int rets = 0;
411 int i;
412
413 if (cl->state != MEI_FILE_CONNECTED)
414 return -ENODEV;
415
Tomas Winklerb210d752012-08-07 00:03:56 +0300416 if (dev->dev_state != MEI_DEV_ENABLED)
Oren Weilab841162011-05-15 13:43:41 +0300417 return -ENODEV;
418
419 dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
420 if (cl->read_pending || cl->read_cb) {
421 dev_dbg(&dev->pdev->dev, "read is pending.\n");
422 return -EBUSY;
423 }
424
425 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
426 if (!cb)
427 return -ENOMEM;
428
429 dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
430 cl->host_client_id, cl->me_client_id);
Tomas Winkler07b509b2012-07-23 14:05:39 +0300431 i = mei_me_cl_by_id(dev, cl->me_client_id);
432 if (i < 0) {
Oren Weilab841162011-05-15 13:43:41 +0300433 rets = -ENODEV;
434 goto unlock;
435 }
436
437 cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
438 cb->response_buffer.data =
Tomas Winkler441ab502011-12-13 23:39:34 +0200439 kmalloc(cb->response_buffer.size, GFP_KERNEL);
Oren Weilab841162011-05-15 13:43:41 +0300440 if (!cb->response_buffer.data) {
441 rets = -ENOMEM;
442 goto unlock;
443 }
444 dev_dbg(&dev->pdev->dev, "allocation call back data success.\n");
445 cb->major_file_operations = MEI_READ;
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200446 /* make sure buffer index is zero before we start */
447 cb->buf_idx = 0;
Oren Weilab841162011-05-15 13:43:41 +0300448 cb->file_private = (void *) cl;
449 cl->read_cb = cb;
450 if (dev->mei_host_buffer_is_empty) {
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300451 dev->mei_host_buffer_is_empty = false;
Tomas Winkler1ccb7b62012-03-14 14:39:42 +0200452 if (mei_send_flow_control(dev, cl)) {
Oren Weilab841162011-05-15 13:43:41 +0300453 rets = -ENODEV;
454 goto unlock;
Oren Weilab841162011-05-15 13:43:41 +0300455 }
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200456 list_add_tail(&cb->list, &dev->read_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300457 } else {
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200458 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300459 }
460 return rets;
461unlock:
Tomas Winkler601a1ef2012-10-09 16:50:20 +0200462 mei_io_cb_free(cb);
Oren Weilab841162011-05-15 13:43:41 +0300463 return rets;
464}
465
466/**
467 * amthi_write - write iamthif data to amthi client
468 *
469 * @dev: the device structure
470 * @cb: mei call back struct
471 *
472 * returns 0 on success, <0 on failure.
473 */
474int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
475{
476 struct mei_msg_hdr mei_hdr;
477 int ret;
478
479 if (!dev || !cb)
480 return -ENODEV;
481
482 dev_dbg(&dev->pdev->dev, "write data to amthi client.\n");
483
484 dev->iamthif_state = MEI_IAMTHIF_WRITING;
485 dev->iamthif_current_cb = cb;
486 dev->iamthif_file_object = cb->file_object;
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300487 dev->iamthif_canceled = false;
488 dev->iamthif_ioctl = true;
Oren Weilab841162011-05-15 13:43:41 +0300489 dev->iamthif_msg_buf_size = cb->request_buffer.size;
490 memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
Tomas Winkler441ab502011-12-13 23:39:34 +0200491 cb->request_buffer.size);
Oren Weilab841162011-05-15 13:43:41 +0300492
493 ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl);
494 if (ret < 0)
495 return ret;
496
497 if (ret && dev->mei_host_buffer_is_empty) {
498 ret = 0;
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300499 dev->mei_host_buffer_is_empty = false;
Tomas Winkler24aadc82012-06-25 23:46:27 +0300500 if (cb->request_buffer.size > mei_hbuf_max_data(dev)) {
501 mei_hdr.length = mei_hbuf_max_data(dev);
Oren Weilab841162011-05-15 13:43:41 +0300502 mei_hdr.msg_complete = 0;
503 } else {
504 mei_hdr.length = cb->request_buffer.size;
505 mei_hdr.msg_complete = 1;
506 }
507
508 mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
509 mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
510 mei_hdr.reserved = 0;
511 dev->iamthif_msg_buf_index += mei_hdr.length;
Tomas Winkler1ccb7b62012-03-14 14:39:42 +0200512 if (mei_write_message(dev, &mei_hdr,
Oren Weilab841162011-05-15 13:43:41 +0300513 (unsigned char *)(dev->iamthif_msg_buf),
514 mei_hdr.length))
515 return -ENODEV;
516
517 if (mei_hdr.msg_complete) {
518 if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
519 return -ENODEV;
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300520 dev->iamthif_flow_control_pending = true;
Oren Weilab841162011-05-15 13:43:41 +0300521 dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
522 dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
523 dev->iamthif_current_cb = cb;
524 dev->iamthif_file_object = cb->file_object;
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200525 list_add_tail(&cb->list, &dev->write_waiting_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300526 } else {
527 dev_dbg(&dev->pdev->dev, "message does not complete, "
528 "so add amthi cb to write list.\n");
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200529 list_add_tail(&cb->list, &dev->write_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300530 }
531 } else {
532 if (!(dev->mei_host_buffer_is_empty))
533 dev_dbg(&dev->pdev->dev, "host buffer is not empty");
534
535 dev_dbg(&dev->pdev->dev, "No flow control credentials, "
536 "so add iamthif cb to write list.\n");
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200537 list_add_tail(&cb->list, &dev->write_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300538 }
539 return 0;
540}
541
542/**
543 * iamthif_ioctl_send_msg - send cmd data to amthi client
544 *
545 * @dev: the device structure
546 *
547 * returns 0 on success, <0 on failure.
548 */
Tomas Winklerc95efb72011-05-25 17:28:21 +0300549void mei_run_next_iamthif_cmd(struct mei_device *dev)
Oren Weilab841162011-05-15 13:43:41 +0300550{
551 struct mei_cl *cl_tmp;
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200552 struct mei_cl_cb *pos = NULL;
553 struct mei_cl_cb *next = NULL;
Oren Weilab841162011-05-15 13:43:41 +0300554 int status;
555
556 if (!dev)
557 return;
558
559 dev->iamthif_msg_buf_size = 0;
560 dev->iamthif_msg_buf_index = 0;
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300561 dev->iamthif_canceled = false;
562 dev->iamthif_ioctl = true;
Oren Weilab841162011-05-15 13:43:41 +0300563 dev->iamthif_state = MEI_IAMTHIF_IDLE;
564 dev->iamthif_timer = 0;
565 dev->iamthif_file_object = NULL;
566
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200567 dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n");
Oren Weilab841162011-05-15 13:43:41 +0300568
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200569 list_for_each_entry_safe(pos, next, &dev->amthi_cmd_list.list, list) {
570 list_del(&pos->list);
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200571 cl_tmp = (struct mei_cl *)pos->file_private;
Oren Weilab841162011-05-15 13:43:41 +0300572
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200573 if (cl_tmp && cl_tmp == &dev->iamthif_cl) {
574 status = amthi_write(dev, pos);
575 if (status) {
576 dev_dbg(&dev->pdev->dev,
577 "amthi write failed status = %d\n",
578 status);
579 return;
Oren Weilab841162011-05-15 13:43:41 +0300580 }
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200581 break;
Oren Weilab841162011-05-15 13:43:41 +0300582 }
583 }
584}
585