diff options
Diffstat (limited to 'drivers/misc/mei/iorw.c')
-rw-r--r-- | drivers/misc/mei/iorw.c | 366 |
1 files changed, 0 insertions, 366 deletions
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c deleted file mode 100644 index eb93a1b53b9b..000000000000 --- a/drivers/misc/mei/iorw.c +++ /dev/null | |||
@@ -1,366 +0,0 @@ | |||
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 | |||
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" | ||
38 | #include <linux/mei.h> | ||
39 | #include "interface.h" | ||
40 | |||
41 | /** | ||
42 | * mei_io_cb_free - free mei_cb_private related memory | ||
43 | * | ||
44 | * @cb: mei callback struct | ||
45 | */ | ||
46 | void 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 | * 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 | */ | ||
63 | struct 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->cl = 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 | */ | ||
90 | int 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 | */ | ||
114 | int 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 | |||
129 | |||
130 | /** | ||
131 | * 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 | */ | ||
140 | |||
141 | int 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 | } | ||
155 | |||
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 | */ | ||
167 | int 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 | long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); | ||
175 | int i; | ||
176 | int err; | ||
177 | int rets; | ||
178 | |||
179 | cl = file->private_data; | ||
180 | if (WARN_ON(!cl || !cl->dev)) | ||
181 | return -ENODEV; | ||
182 | |||
183 | dev = cl->dev; | ||
184 | |||
185 | dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); | ||
186 | |||
187 | /* buffered ioctl cb */ | ||
188 | cb = mei_io_cb_init(cl, file); | ||
189 | if (!cb) { | ||
190 | rets = -ENOMEM; | ||
191 | goto end; | ||
192 | } | ||
193 | |||
194 | cb->fop_type = MEI_FOP_IOCTL; | ||
195 | |||
196 | if (dev->dev_state != MEI_DEV_ENABLED) { | ||
197 | rets = -ENODEV; | ||
198 | goto end; | ||
199 | } | ||
200 | if (cl->state != MEI_FILE_INITIALIZING && | ||
201 | cl->state != MEI_FILE_DISCONNECTED) { | ||
202 | rets = -EBUSY; | ||
203 | goto end; | ||
204 | } | ||
205 | |||
206 | /* find ME client we're trying to connect to */ | ||
207 | i = mei_me_cl_by_uuid(dev, &data->in_client_uuid); | ||
208 | if (i >= 0 && !dev->me_clients[i].props.fixed_address) { | ||
209 | cl->me_client_id = dev->me_clients[i].client_id; | ||
210 | cl->state = MEI_FILE_CONNECTING; | ||
211 | } | ||
212 | |||
213 | dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", | ||
214 | cl->me_client_id); | ||
215 | dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n", | ||
216 | dev->me_clients[i].props.protocol_version); | ||
217 | dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n", | ||
218 | dev->me_clients[i].props.max_msg_length); | ||
219 | |||
220 | /* if we're connecting to amthi client then we will use the | ||
221 | * existing connection | ||
222 | */ | ||
223 | if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) { | ||
224 | dev_dbg(&dev->pdev->dev, "FW Client is amthi\n"); | ||
225 | if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { | ||
226 | rets = -ENODEV; | ||
227 | goto end; | ||
228 | } | ||
229 | clear_bit(cl->host_client_id, dev->host_clients_map); | ||
230 | mei_me_cl_unlink(dev, cl); | ||
231 | |||
232 | kfree(cl); | ||
233 | cl = NULL; | ||
234 | file->private_data = &dev->iamthif_cl; | ||
235 | |||
236 | client = &data->out_client_properties; | ||
237 | client->max_msg_length = | ||
238 | dev->me_clients[i].props.max_msg_length; | ||
239 | client->protocol_version = | ||
240 | dev->me_clients[i].props.protocol_version; | ||
241 | rets = dev->iamthif_cl.status; | ||
242 | |||
243 | goto end; | ||
244 | } | ||
245 | |||
246 | if (cl->state != MEI_FILE_CONNECTING) { | ||
247 | rets = -ENODEV; | ||
248 | goto end; | ||
249 | } | ||
250 | |||
251 | |||
252 | /* prepare the output buffer */ | ||
253 | client = &data->out_client_properties; | ||
254 | client->max_msg_length = dev->me_clients[i].props.max_msg_length; | ||
255 | client->protocol_version = dev->me_clients[i].props.protocol_version; | ||
256 | dev_dbg(&dev->pdev->dev, "Can connect?\n"); | ||
257 | if (dev->mei_host_buffer_is_empty | ||
258 | && !mei_other_client_is_connecting(dev, cl)) { | ||
259 | dev_dbg(&dev->pdev->dev, "Sending Connect Message\n"); | ||
260 | dev->mei_host_buffer_is_empty = false; | ||
261 | if (mei_connect(dev, cl)) { | ||
262 | dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n"); | ||
263 | rets = -ENODEV; | ||
264 | goto end; | ||
265 | } else { | ||
266 | dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); | ||
267 | cl->timer_count = MEI_CONNECT_TIMEOUT; | ||
268 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | ||
269 | } | ||
270 | |||
271 | |||
272 | } else { | ||
273 | dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); | ||
274 | dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); | ||
275 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
276 | } | ||
277 | mutex_unlock(&dev->device_lock); | ||
278 | err = wait_event_timeout(dev->wait_recvd_msg, | ||
279 | (MEI_FILE_CONNECTED == cl->state || | ||
280 | MEI_FILE_DISCONNECTED == cl->state), timeout); | ||
281 | |||
282 | mutex_lock(&dev->device_lock); | ||
283 | if (MEI_FILE_CONNECTED == cl->state) { | ||
284 | dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n"); | ||
285 | rets = cl->status; | ||
286 | goto end; | ||
287 | } else { | ||
288 | dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n", | ||
289 | cl->state); | ||
290 | if (!err) { | ||
291 | dev_dbg(&dev->pdev->dev, | ||
292 | "wait_event_interruptible_timeout failed on client" | ||
293 | " connect message fw response message.\n"); | ||
294 | } | ||
295 | rets = -EFAULT; | ||
296 | |||
297 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | ||
298 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | ||
299 | goto end; | ||
300 | } | ||
301 | rets = 0; | ||
302 | end: | ||
303 | dev_dbg(&dev->pdev->dev, "free connect cb memory."); | ||
304 | mei_io_cb_free(cb); | ||
305 | return rets; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * mei_start_read - the start read client message function. | ||
310 | * | ||
311 | * @dev: the device structure | ||
312 | * @if_num: minor number | ||
313 | * @cl: private data of the file object | ||
314 | * | ||
315 | * returns 0 on success, <0 on failure. | ||
316 | */ | ||
317 | int mei_start_read(struct mei_device *dev, struct mei_cl *cl) | ||
318 | { | ||
319 | struct mei_cl_cb *cb; | ||
320 | int rets; | ||
321 | int i; | ||
322 | |||
323 | if (cl->state != MEI_FILE_CONNECTED) | ||
324 | return -ENODEV; | ||
325 | |||
326 | if (dev->dev_state != MEI_DEV_ENABLED) | ||
327 | return -ENODEV; | ||
328 | |||
329 | if (cl->read_pending || cl->read_cb) { | ||
330 | dev_dbg(&dev->pdev->dev, "read is pending.\n"); | ||
331 | return -EBUSY; | ||
332 | } | ||
333 | i = mei_me_cl_by_id(dev, cl->me_client_id); | ||
334 | if (i < 0) { | ||
335 | dev_err(&dev->pdev->dev, "no such me client %d\n", | ||
336 | cl->me_client_id); | ||
337 | return -ENODEV; | ||
338 | } | ||
339 | |||
340 | cb = mei_io_cb_init(cl, NULL); | ||
341 | if (!cb) | ||
342 | return -ENOMEM; | ||
343 | |||
344 | rets = mei_io_cb_alloc_resp_buf(cb, | ||
345 | dev->me_clients[i].props.max_msg_length); | ||
346 | if (rets) | ||
347 | goto err; | ||
348 | |||
349 | cb->fop_type = MEI_FOP_READ; | ||
350 | cl->read_cb = cb; | ||
351 | if (dev->mei_host_buffer_is_empty) { | ||
352 | dev->mei_host_buffer_is_empty = false; | ||
353 | if (mei_send_flow_control(dev, cl)) { | ||
354 | rets = -ENODEV; | ||
355 | goto err; | ||
356 | } | ||
357 | list_add_tail(&cb->list, &dev->read_list.list); | ||
358 | } else { | ||
359 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
360 | } | ||
361 | return rets; | ||
362 | err: | ||
363 | mei_io_cb_free(cb); | ||
364 | return rets; | ||
365 | } | ||
366 | |||