Merge remote-tracking branch 'char-misc/char-misc-next'
[deliverable/linux.git] / drivers / misc / mei / amthif.c
CommitLineData
19838fb8
TW
1/*
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>
19838fb8
TW
22#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>
1f180359 30#include <linux/slab.h>
19838fb8 31
47a73801 32#include <linux/mei.h>
19838fb8
TW
33
34#include "mei_dev.h"
0edb23fc 35#include "hbm.h"
90e0b5f1 36#include "client.h"
19838fb8 37
1a1aca42
TW
38const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
39 0xac, 0xa8, 0x46, 0xe0,
40 0xff, 0x65, 0x81, 0x4c);
19838fb8
TW
41
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. */
19838fb8 50 dev->iamthif_canceled = false;
19838fb8 51 dev->iamthif_state = MEI_IAMTHIF_IDLE;
4a704575 52 dev->iamthif_stall_timer = 0;
22f96a0e 53 dev->iamthif_open_count = 0;
19838fb8
TW
54}
55
56/**
393b148f 57 * mei_amthif_host_init - mei initialization amthif client.
19838fb8
TW
58 *
59 * @dev: the device structure
d49ed64a 60 * @me_cl: me client
19838fb8 61 *
ce23139c 62 * Return: 0 on success, <0 on failure.
19838fb8 63 */
d49ed64a 64int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
19838fb8 65{
781d0d89 66 struct mei_cl *cl = &dev->iamthif_cl;
d320832f 67 int ret;
19838fb8 68
e728ae27
AU
69 mutex_lock(&dev->device_lock);
70
71 if (mei_cl_is_connected(cl)) {
72 ret = 0;
73 goto out;
74 }
025fb792 75
6222f7bf
TW
76 dev->iamthif_state = MEI_IAMTHIF_IDLE;
77
781d0d89 78 mei_cl_init(cl, dev);
19838fb8 79
7851e008 80 ret = mei_cl_link(cl);
781d0d89 81 if (ret < 0) {
79563db9 82 dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
e728ae27 83 goto out;
781d0d89
TW
84 }
85
d49ed64a 86 ret = mei_cl_connect(cl, me_cl, NULL);
64092858 87
e728ae27
AU
88out:
89 mutex_unlock(&dev->device_lock);
64092858 90 return ret;
19838fb8
TW
91}
92
19838fb8 93/**
c54bf3ab 94 * mei_amthif_read_start - queue message for sending read credential
19838fb8 95 *
c54bf3ab 96 * @cl: host client
3030dc05 97 * @fp: file pointer of message recipient
19838fb8 98 *
a8605ea2 99 * Return: 0 on success, <0 on failure.
19838fb8 100 */
3030dc05 101static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp)
19838fb8 102{
c54bf3ab
TW
103 struct mei_device *dev = cl->dev;
104 struct mei_cl_cb *cb;
19838fb8 105
3030dc05 106 cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp);
35eda92a
AU
107 if (!cb)
108 return -ENOMEM;
19838fb8 109
46978ada 110 cl->rx_flow_ctrl_creds++;
19838fb8 111
c54bf3ab 112 dev->iamthif_state = MEI_IAMTHIF_READING;
97d549b4 113 cl->fp = cb->fp;
19838fb8 114
19838fb8
TW
115 return 0;
116}
117
118/**
ce23139c 119 * mei_amthif_run_next_cmd - send next amt command from queue
19838fb8
TW
120 *
121 * @dev: the device structure
ab5c4a56 122 *
a8605ea2 123 * Return: 0 on success, <0 on failure.
19838fb8 124 */
8660172e 125int mei_amthif_run_next_cmd(struct mei_device *dev)
19838fb8 126{
8660172e 127 struct mei_cl *cl = &dev->iamthif_cl;
05e314e2 128 struct mei_cl_cb *cb;
22393381 129 int ret;
19838fb8 130
19838fb8 131 dev->iamthif_canceled = false;
19838fb8 132
2bf94cab 133 dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
19838fb8 134
140c7553
AU
135 cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
136 typeof(*cb), list);
22393381
AU
137 if (!cb) {
138 dev->iamthif_state = MEI_IAMTHIF_IDLE;
97d549b4 139 cl->fp = NULL;
8660172e 140 return 0;
22393381 141 }
8660172e 142
c54bf3ab 143 list_del_init(&cb->list);
22393381 144 dev->iamthif_state = MEI_IAMTHIF_WRITING;
97d549b4 145 cl->fp = cb->fp;
22393381
AU
146
147 ret = mei_cl_write(cl, cb, false);
148 if (ret < 0)
149 return ret;
150
151 if (cb->completed)
152 cb->status = mei_amthif_read_start(cl, cb->fp);
153
154 return 0;
19838fb8
TW
155}
156
8660172e
TW
157/**
158 * mei_amthif_write - write amthif data to amthif client
159 *
160 * @cl: host client
161 * @cb: mei call back struct
162 *
163 * Return: 0 on success, <0 on failure.
164 */
165int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
166{
167
77b007b1 168 struct mei_device *dev = cl->dev;
8660172e 169
8660172e 170 list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
5cf8b2a9
AU
171
172 /*
173 * The previous request is still in processing, queue this one.
174 */
ca455faf 175 if (dev->iamthif_state != MEI_IAMTHIF_IDLE)
5cf8b2a9
AU
176 return 0;
177
8660172e
TW
178 return mei_amthif_run_next_cmd(dev);
179}
744f0f2f 180
1d9013f0
TW
181/**
182 * mei_amthif_poll - the amthif poll function
183 *
1d9013f0
TW
184 * @file: pointer to file structure
185 * @wait: pointer to poll_table structure
186 *
187 * Return: poll mask
188 *
189 * Locking: called under "dev->device_lock" lock
190 */
ca455faf 191unsigned int mei_amthif_poll(struct file *file, poll_table *wait)
744f0f2f 192{
ca455faf
AU
193 struct mei_cl *cl = file->private_data;
194 struct mei_cl_cb *cb = mei_cl_read_cb(cl, file);
744f0f2f 195 unsigned int mask = 0;
b950ac1d 196
ca455faf
AU
197 poll_wait(file, &cl->rx_wait, wait);
198 if (cb)
1d9013f0 199 mask |= POLLIN | POLLRDNORM;
b950ac1d 200
744f0f2f
TW
201 return mask;
202}
203
19838fb8 204/**
9d098192 205 * mei_amthif_irq_write - write iamthif command in irq thread context.
19838fb8 206 *
19838fb8 207 * @cl: private data of the file object.
a8605ea2 208 * @cb: callback block.
19838fb8
TW
209 * @cmpl_list: complete list.
210 *
a8605ea2 211 * Return: 0, OK; otherwise, error.
19838fb8 212 */
9d098192
TW
213int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
214 struct mei_cl_cb *cmpl_list)
19838fb8 215{
8660172e 216 int ret;
24c656e5 217
8660172e
TW
218 ret = mei_cl_irq_write(cl, cb, cmpl_list);
219 if (ret)
220 return ret;
19838fb8 221
8660172e 222 if (cb->completed)
62e8e6ad 223 cb->status = mei_amthif_read_start(cl, cb->fp);
24c656e5 224
19838fb8
TW
225 return 0;
226}
227
228/**
ce23139c 229 * mei_amthif_irq_read_msg - read routine after ISR to
1a1aca42 230 * handle the read amthif message
19838fb8 231 *
db4756fd 232 * @cl: mei client
1a1aca42 233 * @mei_hdr: header of amthif message
331e4187 234 * @cmpl_list: completed callbacks list
19838fb8 235 *
331e4187 236 * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
19838fb8 237 */
db4756fd 238int mei_amthif_irq_read_msg(struct mei_cl *cl,
5ceb46e2 239 struct mei_msg_hdr *mei_hdr,
331e4187 240 struct mei_cl_cb *cmpl_list)
19838fb8 241{
db4756fd 242 struct mei_device *dev;
331e4187 243 int ret;
19838fb8 244
db4756fd 245 dev = cl->dev;
19838fb8 246
9d04ee11
AU
247 if (dev->iamthif_state != MEI_IAMTHIF_READING) {
248 mei_irq_discard_msg(dev, mei_hdr);
331e4187 249 return 0;
9d04ee11 250 }
19838fb8 251
331e4187
TW
252 ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
253 if (ret)
254 return ret;
19838fb8
TW
255
256 if (!mei_hdr->msg_complete)
257 return 0;
258
2bf94cab 259 dev_dbg(dev->dev, "completed amthif read.\n ");
19838fb8 260 dev->iamthif_stall_timer = 0;
19838fb8 261
19838fb8
TW
262 return 0;
263}
264
265/**
266 * mei_amthif_complete - complete amthif callback.
267 *
9abd8b31 268 * @cl: host client
a8605ea2 269 * @cb: callback block.
19838fb8 270 */
9abd8b31 271void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
19838fb8 272{
9abd8b31 273 struct mei_device *dev = cl->dev;
c54bf3ab 274
32a1dc1d
AU
275 dev_dbg(dev->dev, "completing amthif call back.\n");
276 switch (cb->fop_type) {
277 case MEI_FOP_WRITE:
c54bf3ab
TW
278 if (!cb->status) {
279 dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
280 mei_io_cb_free(cb);
281 return;
282 }
32a1dc1d 283 dev->iamthif_state = MEI_IAMTHIF_IDLE;
97d549b4 284 cl->fp = NULL;
32a1dc1d
AU
285 if (!dev->iamthif_canceled) {
286 /*
287 * in case of error enqueue the write cb to complete
288 * read list so it can be propagated to the reader
289 */
290 list_add_tail(&cb->list, &cl->rd_completed);
291 wake_up_interruptible(&cl->rx_wait);
292 } else {
293 mei_io_cb_free(cb);
294 }
295 break;
296 case MEI_FOP_READ:
297 if (!dev->iamthif_canceled) {
298 list_add_tail(&cb->list, &cl->rd_completed);
299 dev_dbg(dev->dev, "amthif read completed\n");
300 wake_up_interruptible(&cl->rx_wait);
301 } else {
302 mei_io_cb_free(cb);
303 }
c54bf3ab 304
32a1dc1d
AU
305 dev->iamthif_stall_timer = 0;
306 mei_amthif_run_next_cmd(dev);
307 break;
308 default:
309 WARN_ON(1);
19838fb8 310 }
19838fb8
TW
311}
312
a562d5c2
TW
313/**
314 * mei_clear_list - removes all callbacks associated with file
315 * from mei_cb_list
316 *
a562d5c2
TW
317 * @file: file structure
318 * @mei_cb_list: callbacks list
319 *
320 * mei_clear_list is called to clear resources associated with file
321 * when application calls close function or Ctrl-C was pressed
a562d5c2 322 */
c85dba9e
AU
323static void mei_clear_list(const struct file *file,
324 struct list_head *mei_cb_list)
a562d5c2 325{
928fa666 326 struct mei_cl_cb *cb, *next;
32a1dc1d
AU
327
328 list_for_each_entry_safe(cb, next, mei_cb_list, list)
329 if (file == cb->fp)
928fa666 330 mei_io_cb_free(cb);
a562d5c2
TW
331}
332
a562d5c2
TW
333/**
334* mei_amthif_release - the release function
335*
393b148f 336* @dev: device structure
a562d5c2
TW
337* @file: pointer to file structure
338*
a8605ea2 339* Return: 0 on success, <0 on error
a562d5c2
TW
340*/
341int mei_amthif_release(struct mei_device *dev, struct file *file)
342{
97d549b4
AU
343 struct mei_cl *cl = file->private_data;
344
22f96a0e
TW
345 if (dev->iamthif_open_count > 0)
346 dev->iamthif_open_count--;
a562d5c2 347
97d549b4 348 if (cl->fp == file && dev->iamthif_state != MEI_IAMTHIF_IDLE) {
a562d5c2 349
2bf94cab 350 dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
a562d5c2
TW
351 dev->iamthif_state);
352 dev->iamthif_canceled = true;
a562d5c2
TW
353 }
354
c85dba9e
AU
355 mei_clear_list(file, &dev->amthif_cmd_list.list);
356 mei_clear_list(file, &cl->rd_completed);
357 mei_clear_list(file, &dev->ctrl_rd_list.list);
a562d5c2
TW
358
359 return 0;
360}
This page took 0.195893 seconds and 5 git commands to generate.