blob: 8026cbf755db727ab7633c50aa9f2c28ffce4365 [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}
Tomas Winkler664df382012-10-11 16:35:08 +020055/**
56 * mei_io_cb_init - allocate and initialize io callback
57 *
58 * @cl - mei client
59 * @file: pointer to file structure
60 *
61 * returns mei_cl_cb pointer or NULL;
62 */
63struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
64{
65 struct mei_cl_cb *cb;
66
67 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
68 if (!cb)
69 return NULL;
70
71 mei_io_list_init(cb);
72
73 cb->file_object = fp;
74 cb->file_private = cl;
75 cb->buf_idx = 0;
76 return cb;
77}
78
79
80/**
81 * mei_io_cb_alloc_req_buf - allocate request buffer
82 *
83 * @cb - io callback structure
84 * @size: size of the buffer
85 *
86 * returns 0 on success
87 * -EINVAL if cb is NULL
88 * -ENOMEM if allocation failed
89 */
90int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
91{
92 if (!cb)
93 return -EINVAL;
94
95 if (length == 0)
96 return 0;
97
98 cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
99 if (!cb->request_buffer.data)
100 return -ENOMEM;
101 cb->request_buffer.size = length;
102 return 0;
103}
104/**
105 * mei_io_cb_alloc_req_buf - allocate respose buffer
106 *
107 * @cb - io callback structure
108 * @size: size of the buffer
109 *
110 * returns 0 on success
111 * -EINVAL if cb is NULL
112 * -ENOMEM if allocation failed
113 */
114int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
115{
116 if (!cb)
117 return -EINVAL;
118
119 if (length == 0)
120 return 0;
121
122 cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
123 if (!cb->response_buffer.data)
124 return -ENOMEM;
125 cb->response_buffer.size = length;
126 return 0;
127}
128
Tomas Winkler601a1ef2012-10-09 16:50:20 +0200129
130/**
Tomas Winkler07b509b2012-07-23 14:05:39 +0300131 * mei_me_cl_by_id return index to me_clients for client_id
132 *
133 * @dev: the device structure
134 * @client_id: me client id
135 *
136 * Locking: called under "dev->device_lock" lock
137 *
138 * returns index on success, -ENOENT on failure.
139 */
Oren Weilab841162011-05-15 13:43:41 +0300140
Tomas Winkler07b509b2012-07-23 14:05:39 +0300141int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
142{
143 int i;
144 for (i = 0; i < dev->me_clients_num; i++)
145 if (dev->me_clients[i].client_id == client_id)
146 break;
147 if (WARN_ON(dev->me_clients[i].client_id != client_id))
148 return -ENOENT;
149
150 if (i == dev->me_clients_num)
151 return -ENOENT;
152
153 return i;
154}
Oren Weilab841162011-05-15 13:43:41 +0300155
156/**
157 * mei_ioctl_connect_client - the connect to fw client IOCTL function
158 *
159 * @dev: the device structure
160 * @data: IOCTL connect data, input and output parameters
161 * @file: private data of the file object
162 *
163 * Locking: called under "dev->device_lock" lock
164 *
165 * returns 0 on success, <0 on failure.
166 */
167int mei_ioctl_connect_client(struct file *file,
168 struct mei_connect_client_data *data)
169{
170 struct mei_device *dev;
171 struct mei_cl_cb *cb;
172 struct mei_client *client;
173 struct mei_cl *cl;
174 struct mei_cl *cl_pos = NULL;
175 struct mei_cl *cl_next = NULL;
Tomas Winkler3870c322012-11-01 21:17:14 +0200176 long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT);
Oren Weilab841162011-05-15 13:43:41 +0300177 int i;
178 int err;
179 int rets;
180
181 cl = file->private_data;
182 if (WARN_ON(!cl || !cl->dev))
183 return -ENODEV;
184
185 dev = cl->dev;
186
187 dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
188
Oren Weilab841162011-05-15 13:43:41 +0300189 /* buffered ioctl cb */
Tomas Winkler664df382012-10-11 16:35:08 +0200190 cb = mei_io_cb_init(cl, file);
Oren Weilab841162011-05-15 13:43:41 +0300191 if (!cb) {
192 rets = -ENOMEM;
193 goto end;
194 }
Oren Weilab841162011-05-15 13:43:41 +0300195
196 cb->major_file_operations = MEI_IOCTL;
197
Tomas Winklerb210d752012-08-07 00:03:56 +0300198 if (dev->dev_state != MEI_DEV_ENABLED) {
Oren Weilab841162011-05-15 13:43:41 +0300199 rets = -ENODEV;
200 goto end;
201 }
202 if (cl->state != MEI_FILE_INITIALIZING &&
203 cl->state != MEI_FILE_DISCONNECTED) {
204 rets = -EBUSY;
205 goto end;
206 }
207
208 /* find ME client we're trying to connect to */
Tomas Winkler07b509b2012-07-23 14:05:39 +0300209 i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
Oren Weilab841162011-05-15 13:43:41 +0300210 if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
211 cl->me_client_id = dev->me_clients[i].client_id;
212 cl->state = MEI_FILE_CONNECTING;
213 }
214
215 dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
216 cl->me_client_id);
217 dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
218 dev->me_clients[i].props.protocol_version);
219 dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
220 dev->me_clients[i].props.max_msg_length);
221
Justin P. Mattock5f9092f2012-03-12 07:18:09 -0700222 /* if we're connecting to amthi client then we will use the
223 * existing connection
Oren Weilab841162011-05-15 13:43:41 +0300224 */
225 if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
226 dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
227 if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
228 rets = -ENODEV;
229 goto end;
230 }
231 clear_bit(cl->host_client_id, dev->host_clients_map);
232 list_for_each_entry_safe(cl_pos, cl_next,
233 &dev->file_list, link) {
Tomas Winkler0288c7c2011-06-06 10:44:34 +0300234 if (mei_cl_cmp_id(cl, cl_pos)) {
Oren Weilab841162011-05-15 13:43:41 +0300235 dev_dbg(&dev->pdev->dev,
236 "remove file private data node host"
237 " client = %d, ME client = %d.\n",
238 cl_pos->host_client_id,
239 cl_pos->me_client_id);
240 list_del(&cl_pos->link);
241 }
242
243 }
244 dev_dbg(&dev->pdev->dev, "free file private data memory.\n");
245 kfree(cl);
246
247 cl = NULL;
248 file->private_data = &dev->iamthif_cl;
249
250 client = &data->out_client_properties;
251 client->max_msg_length =
252 dev->me_clients[i].props.max_msg_length;
253 client->protocol_version =
254 dev->me_clients[i].props.protocol_version;
255 rets = dev->iamthif_cl.status;
256
257 goto end;
258 }
259
260 if (cl->state != MEI_FILE_CONNECTING) {
261 rets = -ENODEV;
262 goto end;
263 }
264
265
266 /* prepare the output buffer */
267 client = &data->out_client_properties;
268 client->max_msg_length = dev->me_clients[i].props.max_msg_length;
269 client->protocol_version = dev->me_clients[i].props.protocol_version;
270 dev_dbg(&dev->pdev->dev, "Can connect?\n");
271 if (dev->mei_host_buffer_is_empty
272 && !mei_other_client_is_connecting(dev, cl)) {
273 dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300274 dev->mei_host_buffer_is_empty = false;
Tomas Winkler1ccb7b62012-03-14 14:39:42 +0200275 if (mei_connect(dev, cl)) {
Oren Weilab841162011-05-15 13:43:41 +0300276 dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
277 rets = -ENODEV;
278 goto end;
279 } else {
280 dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
281 cl->timer_count = MEI_CONNECT_TIMEOUT;
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200282 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300283 }
284
285
286 } else {
287 dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
Oren Weilab841162011-05-15 13:43:41 +0300288 dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200289 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300290 }
291 mutex_unlock(&dev->device_lock);
292 err = wait_event_timeout(dev->wait_recvd_msg,
293 (MEI_FILE_CONNECTED == cl->state ||
Tomas Winkler3870c322012-11-01 21:17:14 +0200294 MEI_FILE_DISCONNECTED == cl->state), timeout);
Oren Weilab841162011-05-15 13:43:41 +0300295
296 mutex_lock(&dev->device_lock);
297 if (MEI_FILE_CONNECTED == cl->state) {
298 dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
299 rets = cl->status;
300 goto end;
301 } else {
302 dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
303 cl->state);
304 if (!err) {
305 dev_dbg(&dev->pdev->dev,
306 "wait_event_interruptible_timeout failed on client"
307 " connect message fw response message.\n");
308 }
309 rets = -EFAULT;
310
Tomas Winkler0288c7c2011-06-06 10:44:34 +0300311 mei_io_list_flush(&dev->ctrl_rd_list, cl);
312 mei_io_list_flush(&dev->ctrl_wr_list, cl);
Oren Weilab841162011-05-15 13:43:41 +0300313 goto end;
314 }
315 rets = 0;
316end:
317 dev_dbg(&dev->pdev->dev, "free connect cb memory.");
Tomas Winkler601a1ef2012-10-09 16:50:20 +0200318 mei_io_cb_free(cb);
Oren Weilab841162011-05-15 13:43:41 +0300319 return rets;
320}
321
322/**
323 * find_amthi_read_list_entry - finds a amthilist entry for current file
324 *
325 * @dev: the device structure
326 * @file: pointer to file object
327 *
328 * returns returned a list entry on success, NULL on failure.
329 */
330struct mei_cl_cb *find_amthi_read_list_entry(
331 struct mei_device *dev,
332 struct file *file)
333{
334 struct mei_cl *cl_temp;
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200335 struct mei_cl_cb *pos = NULL;
336 struct mei_cl_cb *next = NULL;
Oren Weilab841162011-05-15 13:43:41 +0300337
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200338 list_for_each_entry_safe(pos, next,
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200339 &dev->amthi_read_complete_list.list, list) {
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200340 cl_temp = (struct mei_cl *)pos->file_private;
341 if (cl_temp && cl_temp == &dev->iamthif_cl &&
342 pos->file_object == file)
343 return pos;
Oren Weilab841162011-05-15 13:43:41 +0300344 }
345 return NULL;
346}
347
348/**
349 * amthi_read - read data from AMTHI client
350 *
351 * @dev: the device structure
352 * @if_num: minor number
353 * @file: pointer to file object
354 * @*ubuf: pointer to user data in user space
355 * @length: data length to read
356 * @offset: data read offset
357 *
358 * Locking: called under "dev->device_lock" lock
359 *
360 * returns
361 * returned data length on success,
362 * zero if no data to read,
363 * negative on failure.
364 */
365int amthi_read(struct mei_device *dev, struct file *file,
Tomas Winkler441ab502011-12-13 23:39:34 +0200366 char __user *ubuf, size_t length, loff_t *offset)
Oren Weilab841162011-05-15 13:43:41 +0300367{
368 int rets;
369 int wait_ret;
370 struct mei_cl_cb *cb = NULL;
371 struct mei_cl *cl = file->private_data;
372 unsigned long timeout;
373 int i;
374
375 /* Only Posible if we are in timeout */
376 if (!cl || cl != &dev->iamthif_cl) {
377 dev_dbg(&dev->pdev->dev, "bad file ext.\n");
378 return -ETIMEDOUT;
379 }
380
Tomas Winkler07b509b2012-07-23 14:05:39 +0300381 i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
Oren Weilab841162011-05-15 13:43:41 +0300382
Tomas Winkler07b509b2012-07-23 14:05:39 +0300383 if (i < 0) {
Oren Weilab841162011-05-15 13:43:41 +0300384 dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
385 return -ENODEV;
386 }
Oren Weilab841162011-05-15 13:43:41 +0300387 dev_dbg(&dev->pdev->dev, "checking amthi data\n");
388 cb = find_amthi_read_list_entry(dev, file);
389
390 /* Check for if we can block or not*/
391 if (cb == NULL && file->f_flags & O_NONBLOCK)
392 return -EAGAIN;
393
394
395 dev_dbg(&dev->pdev->dev, "waiting for amthi data\n");
396 while (cb == NULL) {
397 /* unlock the Mutex */
398 mutex_unlock(&dev->device_lock);
399
400 wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
401 (cb = find_amthi_read_list_entry(dev, file)));
402
403 if (wait_ret)
404 return -ERESTARTSYS;
405
406 dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
407
408 /* Locking again the Mutex */
409 mutex_lock(&dev->device_lock);
410 }
411
412
413 dev_dbg(&dev->pdev->dev, "Got amthi data\n");
414 dev->iamthif_timer = 0;
415
416 if (cb) {
Tomas Winkler3870c322012-11-01 21:17:14 +0200417 timeout = cb->read_time +
418 mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
Oren Weilab841162011-05-15 13:43:41 +0300419 dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
420 timeout);
421
422 if (time_after(jiffies, timeout)) {
423 dev_dbg(&dev->pdev->dev, "amthi Time out\n");
424 /* 15 sec for the message has expired */
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200425 list_del(&cb->list);
Oren Weilab841162011-05-15 13:43:41 +0300426 rets = -ETIMEDOUT;
427 goto free;
428 }
429 }
430 /* if the whole message will fit remove it from the list */
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200431 if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200432 list_del(&cb->list);
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200433 else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
Oren Weilab841162011-05-15 13:43:41 +0300434 /* end of the message has been reached */
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200435 list_del(&cb->list);
Oren Weilab841162011-05-15 13:43:41 +0300436 rets = 0;
437 goto free;
438 }
439 /* else means that not full buffer will be read and do not
440 * remove message from deletion list
441 */
442
443 dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n",
444 cb->response_buffer.size);
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200445 dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx);
Oren Weilab841162011-05-15 13:43:41 +0300446
447 /* length is being turncated to PAGE_SIZE, however,
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200448 * the buf_idx may point beyond */
449 length = min_t(size_t, length, (cb->buf_idx - *offset));
Oren Weilab841162011-05-15 13:43:41 +0300450
Tomas Winkler441ab502011-12-13 23:39:34 +0200451 if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
Oren Weilab841162011-05-15 13:43:41 +0300452 rets = -EFAULT;
453 else {
454 rets = length;
Tomas Winklerebb108ef2012-10-09 16:50:16 +0200455 if ((*offset + length) < cb->buf_idx) {
Oren Weilab841162011-05-15 13:43:41 +0300456 *offset += length;
457 goto out;
458 }
459 }
460free:
461 dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n");
462 *offset = 0;
Tomas Winkler601a1ef2012-10-09 16:50:20 +0200463 mei_io_cb_free(cb);
Oren Weilab841162011-05-15 13:43:41 +0300464out:
465 return rets;
466}
467
468/**
469 * mei_start_read - the start read client message function.
470 *
471 * @dev: the device structure
472 * @if_num: minor number
473 * @cl: private data of the file object
474 *
475 * returns 0 on success, <0 on failure.
476 */
477int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
478{
479 struct mei_cl_cb *cb;
Tomas Winkler664df382012-10-11 16:35:08 +0200480 int rets;
Oren Weilab841162011-05-15 13:43:41 +0300481 int i;
482
483 if (cl->state != MEI_FILE_CONNECTED)
484 return -ENODEV;
485
Tomas Winklerb210d752012-08-07 00:03:56 +0300486 if (dev->dev_state != MEI_DEV_ENABLED)
Oren Weilab841162011-05-15 13:43:41 +0300487 return -ENODEV;
488
Oren Weilab841162011-05-15 13:43:41 +0300489 if (cl->read_pending || cl->read_cb) {
490 dev_dbg(&dev->pdev->dev, "read is pending.\n");
491 return -EBUSY;
492 }
Tomas Winkler664df382012-10-11 16:35:08 +0200493 i = mei_me_cl_by_id(dev, cl->me_client_id);
494 if (i < 0) {
495 dev_err(&dev->pdev->dev, "no such me client %d\n",
496 cl->me_client_id);
497 return -ENODEV;
498 }
Oren Weilab841162011-05-15 13:43:41 +0300499
Tomas Winkler664df382012-10-11 16:35:08 +0200500 cb = mei_io_cb_init(cl, NULL);
Oren Weilab841162011-05-15 13:43:41 +0300501 if (!cb)
502 return -ENOMEM;
503
Tomas Winkler664df382012-10-11 16:35:08 +0200504 rets = mei_io_cb_alloc_resp_buf(cb,
505 dev->me_clients[i].props.max_msg_length);
506 if (rets)
507 goto err;
Oren Weilab841162011-05-15 13:43:41 +0300508
Oren Weilab841162011-05-15 13:43:41 +0300509 cb->major_file_operations = MEI_READ;
Oren Weilab841162011-05-15 13:43:41 +0300510 cl->read_cb = cb;
511 if (dev->mei_host_buffer_is_empty) {
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300512 dev->mei_host_buffer_is_empty = false;
Tomas Winkler1ccb7b62012-03-14 14:39:42 +0200513 if (mei_send_flow_control(dev, cl)) {
Oren Weilab841162011-05-15 13:43:41 +0300514 rets = -ENODEV;
Tomas Winkler664df382012-10-11 16:35:08 +0200515 goto err;
Oren Weilab841162011-05-15 13:43:41 +0300516 }
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200517 list_add_tail(&cb->list, &dev->read_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300518 } else {
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200519 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300520 }
521 return rets;
Tomas Winkler664df382012-10-11 16:35:08 +0200522err:
Tomas Winkler601a1ef2012-10-09 16:50:20 +0200523 mei_io_cb_free(cb);
Oren Weilab841162011-05-15 13:43:41 +0300524 return rets;
525}
526
527/**
528 * amthi_write - write iamthif data to amthi client
529 *
530 * @dev: the device structure
531 * @cb: mei call back struct
532 *
533 * returns 0 on success, <0 on failure.
534 */
535int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
536{
537 struct mei_msg_hdr mei_hdr;
538 int ret;
539
540 if (!dev || !cb)
541 return -ENODEV;
542
543 dev_dbg(&dev->pdev->dev, "write data to amthi client.\n");
544
545 dev->iamthif_state = MEI_IAMTHIF_WRITING;
546 dev->iamthif_current_cb = cb;
547 dev->iamthif_file_object = cb->file_object;
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300548 dev->iamthif_canceled = false;
549 dev->iamthif_ioctl = true;
Oren Weilab841162011-05-15 13:43:41 +0300550 dev->iamthif_msg_buf_size = cb->request_buffer.size;
551 memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
Tomas Winkler441ab502011-12-13 23:39:34 +0200552 cb->request_buffer.size);
Oren Weilab841162011-05-15 13:43:41 +0300553
554 ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl);
555 if (ret < 0)
556 return ret;
557
558 if (ret && dev->mei_host_buffer_is_empty) {
559 ret = 0;
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300560 dev->mei_host_buffer_is_empty = false;
Tomas Winkler24aadc82012-06-25 23:46:27 +0300561 if (cb->request_buffer.size > mei_hbuf_max_data(dev)) {
562 mei_hdr.length = mei_hbuf_max_data(dev);
Oren Weilab841162011-05-15 13:43:41 +0300563 mei_hdr.msg_complete = 0;
564 } else {
565 mei_hdr.length = cb->request_buffer.size;
566 mei_hdr.msg_complete = 1;
567 }
568
569 mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
570 mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
571 mei_hdr.reserved = 0;
572 dev->iamthif_msg_buf_index += mei_hdr.length;
Tomas Winkler1ccb7b62012-03-14 14:39:42 +0200573 if (mei_write_message(dev, &mei_hdr,
Oren Weilab841162011-05-15 13:43:41 +0300574 (unsigned char *)(dev->iamthif_msg_buf),
575 mei_hdr.length))
576 return -ENODEV;
577
578 if (mei_hdr.msg_complete) {
579 if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
580 return -ENODEV;
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300581 dev->iamthif_flow_control_pending = true;
Oren Weilab841162011-05-15 13:43:41 +0300582 dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
583 dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
584 dev->iamthif_current_cb = cb;
585 dev->iamthif_file_object = cb->file_object;
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200586 list_add_tail(&cb->list, &dev->write_waiting_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300587 } else {
588 dev_dbg(&dev->pdev->dev, "message does not complete, "
589 "so add amthi cb to write list.\n");
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200590 list_add_tail(&cb->list, &dev->write_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300591 }
592 } else {
593 if (!(dev->mei_host_buffer_is_empty))
594 dev_dbg(&dev->pdev->dev, "host buffer is not empty");
595
596 dev_dbg(&dev->pdev->dev, "No flow control credentials, "
597 "so add iamthif cb to write list.\n");
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200598 list_add_tail(&cb->list, &dev->write_list.list);
Oren Weilab841162011-05-15 13:43:41 +0300599 }
600 return 0;
601}
602
603/**
604 * iamthif_ioctl_send_msg - send cmd data to amthi client
605 *
606 * @dev: the device structure
607 *
608 * returns 0 on success, <0 on failure.
609 */
Tomas Winklerc95efb72011-05-25 17:28:21 +0300610void mei_run_next_iamthif_cmd(struct mei_device *dev)
Oren Weilab841162011-05-15 13:43:41 +0300611{
612 struct mei_cl *cl_tmp;
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200613 struct mei_cl_cb *pos = NULL;
614 struct mei_cl_cb *next = NULL;
Oren Weilab841162011-05-15 13:43:41 +0300615 int status;
616
617 if (!dev)
618 return;
619
620 dev->iamthif_msg_buf_size = 0;
621 dev->iamthif_msg_buf_index = 0;
Tomas Winklereb9af0a2011-05-25 17:28:22 +0300622 dev->iamthif_canceled = false;
623 dev->iamthif_ioctl = true;
Oren Weilab841162011-05-15 13:43:41 +0300624 dev->iamthif_state = MEI_IAMTHIF_IDLE;
625 dev->iamthif_timer = 0;
626 dev->iamthif_file_object = NULL;
627
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200628 dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n");
Oren Weilab841162011-05-15 13:43:41 +0300629
Tomas Winklerfb601ad2012-10-15 12:06:48 +0200630 list_for_each_entry_safe(pos, next, &dev->amthi_cmd_list.list, list) {
631 list_del(&pos->list);
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200632 cl_tmp = (struct mei_cl *)pos->file_private;
Oren Weilab841162011-05-15 13:43:41 +0300633
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200634 if (cl_tmp && cl_tmp == &dev->iamthif_cl) {
635 status = amthi_write(dev, pos);
636 if (status) {
637 dev_dbg(&dev->pdev->dev,
638 "amthi write failed status = %d\n",
639 status);
640 return;
Oren Weilab841162011-05-15 13:43:41 +0300641 }
Tomas Winklerb7cd2d92011-11-27 21:43:34 +0200642 break;
Oren Weilab841162011-05-15 13:43:41 +0300643 }
644 }
645}
646