082462ea90c92ec47cbf5bd7695ea705cfcecea0
[muen/linux.git] / drivers / misc / mei / amthif.c
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>
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>
30 #include <linux/slab.h>
31
32 #include <linux/mei.h>
33
34 #include "mei_dev.h"
35 #include "hbm.h"
36 #include "client.h"
37
38 const uuid_le mei_amthif_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
39                                          0xac, 0xa8, 0x46, 0xe0,
40                                          0xff, 0x65, 0x81, 0x4c);
41
42 /**
43  * mei_amthif_reset_params - initializes mei device iamthif
44  *
45  * @dev: the device structure
46  */
47 void mei_amthif_reset_params(struct mei_device *dev)
48 {
49         /* reset iamthif parameters. */
50         dev->iamthif_canceled = false;
51         dev->iamthif_state = MEI_IAMTHIF_IDLE;
52         dev->iamthif_stall_timer = 0;
53         dev->iamthif_open_count = 0;
54 }
55
56 /**
57  * mei_amthif_host_init - mei initialization amthif client.
58  *
59  * @dev: the device structure
60  * @me_cl: me client
61  *
62  * Return: 0 on success, <0 on failure.
63  */
64 int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
65 {
66         struct mei_cl *cl = &dev->iamthif_cl;
67         int ret;
68
69         mutex_lock(&dev->device_lock);
70
71         if (mei_cl_is_connected(cl)) {
72                 ret = 0;
73                 goto out;
74         }
75
76         dev->iamthif_state = MEI_IAMTHIF_IDLE;
77
78         mei_cl_init(cl, dev);
79
80         ret = mei_cl_link(cl);
81         if (ret < 0) {
82                 dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
83                 goto out;
84         }
85
86         ret = mei_cl_connect(cl, me_cl, NULL);
87
88 out:
89         mutex_unlock(&dev->device_lock);
90         return ret;
91 }
92
93 /**
94  * mei_amthif_read_start - queue message for sending read credential
95  *
96  * @cl: host client
97  * @fp: file pointer of message recipient
98  *
99  * Return: 0 on success, <0 on failure.
100  */
101 static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp)
102 {
103         struct mei_device *dev = cl->dev;
104         struct mei_cl_cb *cb;
105
106         cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp);
107         if (!cb)
108                 return -ENOMEM;
109
110         cl->rx_flow_ctrl_creds++;
111
112         dev->iamthif_state = MEI_IAMTHIF_READING;
113         cl->fp = cb->fp;
114
115         return 0;
116 }
117
118 /**
119  * mei_amthif_run_next_cmd - send next amt command from queue
120  *
121  * @dev: the device structure
122  *
123  * Return: 0 on success, <0 on failure.
124  */
125 int mei_amthif_run_next_cmd(struct mei_device *dev)
126 {
127         struct mei_cl *cl = &dev->iamthif_cl;
128         struct mei_cl_cb *cb;
129         int ret;
130
131         dev->iamthif_canceled = false;
132
133         dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
134
135         cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
136                                         typeof(*cb), list);
137         if (!cb) {
138                 dev->iamthif_state = MEI_IAMTHIF_IDLE;
139                 cl->fp = NULL;
140                 return 0;
141         }
142
143         list_del_init(&cb->list);
144         dev->iamthif_state = MEI_IAMTHIF_WRITING;
145         cl->fp = cb->fp;
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;
155 }
156
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  */
165 int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
166 {
167
168         struct mei_device *dev = cl->dev;
169
170         list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
171
172         /*
173          * The previous request is still in processing, queue this one.
174          */
175         if (dev->iamthif_state != MEI_IAMTHIF_IDLE)
176                 return 0;
177
178         return mei_amthif_run_next_cmd(dev);
179 }
180
181 /**
182  * mei_amthif_poll - the amthif poll function
183  *
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  */
191 unsigned int mei_amthif_poll(struct file *file, poll_table *wait)
192 {
193         struct mei_cl *cl = file->private_data;
194         struct mei_cl_cb *cb = mei_cl_read_cb(cl, file);
195         unsigned int mask = 0;
196
197         poll_wait(file, &cl->rx_wait, wait);
198         if (cb)
199                 mask |= POLLIN | POLLRDNORM;
200
201         return mask;
202 }
203
204 /**
205  * mei_amthif_irq_write - write iamthif command in irq thread context.
206  *
207  * @cl: private data of the file object.
208  * @cb: callback block.
209  * @cmpl_list: complete list.
210  *
211  * Return: 0, OK; otherwise, error.
212  */
213 int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
214                          struct mei_cl_cb *cmpl_list)
215 {
216         int ret;
217
218         ret = mei_cl_irq_write(cl, cb, cmpl_list);
219         if (ret)
220                 return ret;
221
222         if (cb->completed)
223                 cb->status = mei_amthif_read_start(cl, cb->fp);
224
225         return 0;
226 }
227
228 /**
229  * mei_amthif_irq_read_msg - read routine after ISR to
230  *                      handle the read amthif message
231  *
232  * @cl: mei client
233  * @mei_hdr: header of amthif message
234  * @cmpl_list: completed callbacks list
235  *
236  * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
237  */
238 int mei_amthif_irq_read_msg(struct mei_cl *cl,
239                             struct mei_msg_hdr *mei_hdr,
240                             struct mei_cl_cb *cmpl_list)
241 {
242         struct mei_device *dev;
243         int ret;
244
245         dev = cl->dev;
246
247         if (dev->iamthif_state != MEI_IAMTHIF_READING) {
248                 mei_irq_discard_msg(dev, mei_hdr);
249                 return 0;
250         }
251
252         ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
253         if (ret)
254                 return ret;
255
256         if (!mei_hdr->msg_complete)
257                 return 0;
258
259         dev_dbg(dev->dev, "completed amthif read.\n ");
260         dev->iamthif_stall_timer = 0;
261
262         return 0;
263 }
264
265 /**
266  * mei_amthif_complete - complete amthif callback.
267  *
268  * @cl: host client
269  * @cb: callback block.
270  */
271 void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
272 {
273         struct mei_device *dev = cl->dev;
274
275         dev_dbg(dev->dev, "completing amthif call back.\n");
276         switch (cb->fop_type) {
277         case MEI_FOP_WRITE:
278                 if (!cb->status) {
279                         dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
280                         mei_io_cb_free(cb);
281                         return;
282                 }
283                 dev->iamthif_state = MEI_IAMTHIF_IDLE;
284                 cl->fp = NULL;
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                 }
304
305                 dev->iamthif_stall_timer = 0;
306                 mei_amthif_run_next_cmd(dev);
307                 break;
308         default:
309                 WARN_ON(1);
310         }
311 }
312
313 /**
314  * mei_clear_list - removes all callbacks associated with file
315  *              from mei_cb_list
316  *
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
322  */
323 static void mei_clear_list(const struct file *file,
324                            struct list_head *mei_cb_list)
325 {
326         struct mei_cl_cb *cb, *next;
327
328         list_for_each_entry_safe(cb, next, mei_cb_list, list)
329                 if (file == cb->fp)
330                         mei_io_cb_free(cb);
331 }
332
333 /**
334 * mei_amthif_release - the release function
335 *
336 *  @dev: device structure
337 *  @file: pointer to file structure
338 *
339 *  Return: 0 on success, <0 on error
340 */
341 int mei_amthif_release(struct mei_device *dev, struct file *file)
342 {
343         struct mei_cl *cl = file->private_data;
344
345         if (dev->iamthif_open_count > 0)
346                 dev->iamthif_open_count--;
347
348         if (cl->fp == file && dev->iamthif_state != MEI_IAMTHIF_IDLE) {
349
350                 dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
351                     dev->iamthif_state);
352                 dev->iamthif_canceled = true;
353         }
354
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);
358
359         return 0;
360 }