diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2013-01-08 16:07:13 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-08 19:40:44 -0500 |
commit | 9ca9050b3df690d9d44e39424ab2a531120af936 (patch) | |
tree | 06664064214caea9635e66025ad342f60cfc9662 | |
parent | 0edb23fc3451c84350edcc999c023d225a49530d (diff) |
mei: move client functions to client.c
This file now contains me and host client functions
and also io callback helpers
We also kill iorw.c which is no longer needed
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/misc/mei/Makefile | 2 | ||||
-rw-r--r-- | drivers/misc/mei/client.c (renamed from drivers/misc/mei/iorw.c) | 377 | ||||
-rw-r--r-- | drivers/misc/mei/init.c | 252 | ||||
-rw-r--r-- | drivers/misc/mei/interface.c | 96 |
4 files changed, 361 insertions, 366 deletions
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index 1f382a5ca3a6..67f543ab234f 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile | |||
@@ -7,7 +7,7 @@ mei-objs := init.o | |||
7 | mei-objs += hbm.o | 7 | mei-objs += hbm.o |
8 | mei-objs += interrupt.o | 8 | mei-objs += interrupt.o |
9 | mei-objs += interface.o | 9 | mei-objs += interface.o |
10 | mei-objs += iorw.o | ||
11 | mei-objs += main.o | 10 | mei-objs += main.o |
12 | mei-objs += amthif.o | 11 | mei-objs += amthif.o |
13 | mei-objs += wd.o | 12 | mei-objs += wd.o |
13 | mei-objs += client.o | ||
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/client.c index 4328c2d2ca54..19f62073fa67 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/client.c | |||
@@ -14,24 +14,10 @@ | |||
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 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> | 17 | #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> | 18 | #include <linux/sched.h> |
31 | #include <linux/uuid.h> | 19 | #include <linux/wait.h> |
32 | #include <linux/jiffies.h> | 20 | #include <linux/delay.h> |
33 | #include <linux/uaccess.h> | ||
34 | |||
35 | 21 | ||
36 | #include <linux/mei.h> | 22 | #include <linux/mei.h> |
37 | 23 | ||
@@ -39,6 +25,24 @@ | |||
39 | #include "hbm.h" | 25 | #include "hbm.h" |
40 | #include "interface.h" | 26 | #include "interface.h" |
41 | 27 | ||
28 | |||
29 | /** | ||
30 | * mei_io_list_flush - removes list entry belonging to cl. | ||
31 | * | ||
32 | * @list: An instance of our list structure | ||
33 | * @cl: host client | ||
34 | */ | ||
35 | void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) | ||
36 | { | ||
37 | struct mei_cl_cb *cb; | ||
38 | struct mei_cl_cb *next; | ||
39 | |||
40 | list_for_each_entry_safe(cb, next, &list->list, list) { | ||
41 | if (cb->cl && mei_cl_cmp_id(cl, cb->cl)) | ||
42 | list_del(&cb->list); | ||
43 | } | ||
44 | } | ||
45 | |||
42 | /** | 46 | /** |
43 | * mei_io_cb_free - free mei_cb_private related memory | 47 | * mei_io_cb_free - free mei_cb_private related memory |
44 | * | 48 | * |
@@ -53,6 +57,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb) | |||
53 | kfree(cb->response_buffer.data); | 57 | kfree(cb->response_buffer.data); |
54 | kfree(cb); | 58 | kfree(cb); |
55 | } | 59 | } |
60 | |||
56 | /** | 61 | /** |
57 | * mei_io_cb_init - allocate and initialize io callback | 62 | * mei_io_cb_init - allocate and initialize io callback |
58 | * | 63 | * |
@@ -77,7 +82,6 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) | |||
77 | return cb; | 82 | return cb; |
78 | } | 83 | } |
79 | 84 | ||
80 | |||
81 | /** | 85 | /** |
82 | * mei_io_cb_alloc_req_buf - allocate request buffer | 86 | * mei_io_cb_alloc_req_buf - allocate request buffer |
83 | * | 87 | * |
@@ -128,6 +132,50 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) | |||
128 | } | 132 | } |
129 | 133 | ||
130 | 134 | ||
135 | |||
136 | /** | ||
137 | * mei_cl_flush_queues - flushes queue lists belonging to cl. | ||
138 | * | ||
139 | * @dev: the device structure | ||
140 | * @cl: host client | ||
141 | */ | ||
142 | int mei_cl_flush_queues(struct mei_cl *cl) | ||
143 | { | ||
144 | if (!cl || !cl->dev) | ||
145 | return -EINVAL; | ||
146 | |||
147 | dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n"); | ||
148 | mei_io_list_flush(&cl->dev->read_list, cl); | ||
149 | mei_io_list_flush(&cl->dev->write_list, cl); | ||
150 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); | ||
151 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); | ||
152 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); | ||
153 | mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); | ||
154 | mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * mei_me_cl_by_uuid - locate index of me client | ||
160 | * | ||
161 | * @dev: mei device | ||
162 | * returns me client index or -ENOENT if not found | ||
163 | */ | ||
164 | int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid) | ||
165 | { | ||
166 | int i, res = -ENOENT; | ||
167 | |||
168 | for (i = 0; i < dev->me_clients_num; ++i) | ||
169 | if (uuid_le_cmp(*uuid, | ||
170 | dev->me_clients[i].props.protocol_name) == 0) { | ||
171 | res = i; | ||
172 | break; | ||
173 | } | ||
174 | |||
175 | return res; | ||
176 | } | ||
177 | |||
178 | |||
131 | /** | 179 | /** |
132 | * mei_me_cl_by_id return index to me_clients for client_id | 180 | * mei_me_cl_by_id return index to me_clients for client_id |
133 | * | 181 | * |
@@ -155,6 +203,301 @@ int mei_me_cl_by_id(struct mei_device *dev, u8 client_id) | |||
155 | } | 203 | } |
156 | 204 | ||
157 | /** | 205 | /** |
206 | * mei_cl_init - initializes intialize cl. | ||
207 | * | ||
208 | * @cl: host client to be initialized | ||
209 | * @dev: mei device | ||
210 | */ | ||
211 | void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) | ||
212 | { | ||
213 | memset(cl, 0, sizeof(struct mei_cl)); | ||
214 | init_waitqueue_head(&cl->wait); | ||
215 | init_waitqueue_head(&cl->rx_wait); | ||
216 | init_waitqueue_head(&cl->tx_wait); | ||
217 | INIT_LIST_HEAD(&cl->link); | ||
218 | cl->reading_state = MEI_IDLE; | ||
219 | cl->writing_state = MEI_IDLE; | ||
220 | cl->dev = dev; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * mei_cl_allocate - allocates cl structure and sets it up. | ||
225 | * | ||
226 | * @dev: mei device | ||
227 | * returns The allocated file or NULL on failure | ||
228 | */ | ||
229 | struct mei_cl *mei_cl_allocate(struct mei_device *dev) | ||
230 | { | ||
231 | struct mei_cl *cl; | ||
232 | |||
233 | cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); | ||
234 | if (!cl) | ||
235 | return NULL; | ||
236 | |||
237 | mei_cl_init(cl, dev); | ||
238 | |||
239 | return cl; | ||
240 | } | ||
241 | |||
242 | |||
243 | /** | ||
244 | * mei_me_cl_link - create link between host and me clinet and add | ||
245 | * me_cl to the list | ||
246 | * | ||
247 | * @dev: the device structure | ||
248 | * @cl: link between me and host client assocated with opened file descriptor | ||
249 | * @uuid: uuid of ME client | ||
250 | * @client_id: id of the host client | ||
251 | * | ||
252 | * returns ME client index if ME client | ||
253 | * -EINVAL on incorrect values | ||
254 | * -ENONET if client not found | ||
255 | */ | ||
256 | int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, | ||
257 | const uuid_le *uuid, u8 host_cl_id) | ||
258 | { | ||
259 | int i; | ||
260 | |||
261 | if (!dev || !cl || !uuid) | ||
262 | return -EINVAL; | ||
263 | |||
264 | /* check for valid client id */ | ||
265 | i = mei_me_cl_by_uuid(dev, uuid); | ||
266 | if (i >= 0) { | ||
267 | cl->me_client_id = dev->me_clients[i].client_id; | ||
268 | cl->state = MEI_FILE_CONNECTING; | ||
269 | cl->host_client_id = host_cl_id; | ||
270 | |||
271 | list_add_tail(&cl->link, &dev->file_list); | ||
272 | return (u8)i; | ||
273 | } | ||
274 | |||
275 | return -ENOENT; | ||
276 | } | ||
277 | /** | ||
278 | * mei_me_cl_unlink - remove me_cl from the list | ||
279 | * | ||
280 | * @dev: the device structure | ||
281 | * @host_client_id: host client id to be removed | ||
282 | */ | ||
283 | void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) | ||
284 | { | ||
285 | struct mei_cl *pos, *next; | ||
286 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { | ||
287 | if (cl->host_client_id == pos->host_client_id) { | ||
288 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", | ||
289 | pos->host_client_id, pos->me_client_id); | ||
290 | list_del_init(&pos->link); | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | |||
297 | void mei_host_client_init(struct work_struct *work) | ||
298 | { | ||
299 | struct mei_device *dev = container_of(work, | ||
300 | struct mei_device, init_work); | ||
301 | struct mei_client_properties *client_props; | ||
302 | int i; | ||
303 | |||
304 | mutex_lock(&dev->device_lock); | ||
305 | |||
306 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | ||
307 | dev->open_handle_count = 0; | ||
308 | |||
309 | /* | ||
310 | * Reserving the first three client IDs | ||
311 | * 0: Reserved for MEI Bus Message communications | ||
312 | * 1: Reserved for Watchdog | ||
313 | * 2: Reserved for AMTHI | ||
314 | */ | ||
315 | bitmap_set(dev->host_clients_map, 0, 3); | ||
316 | |||
317 | for (i = 0; i < dev->me_clients_num; i++) { | ||
318 | client_props = &dev->me_clients[i].props; | ||
319 | |||
320 | if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) | ||
321 | mei_amthif_host_init(dev); | ||
322 | else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) | ||
323 | mei_wd_host_init(dev); | ||
324 | } | ||
325 | |||
326 | dev->dev_state = MEI_DEV_ENABLED; | ||
327 | |||
328 | mutex_unlock(&dev->device_lock); | ||
329 | } | ||
330 | |||
331 | |||
332 | /** | ||
333 | * mei_disconnect_host_client - sends disconnect message to fw from host client. | ||
334 | * | ||
335 | * @dev: the device structure | ||
336 | * @cl: private data of the file object | ||
337 | * | ||
338 | * Locking: called under "dev->device_lock" lock | ||
339 | * | ||
340 | * returns 0 on success, <0 on failure. | ||
341 | */ | ||
342 | int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | ||
343 | { | ||
344 | struct mei_cl_cb *cb; | ||
345 | int rets, err; | ||
346 | |||
347 | if (!dev || !cl) | ||
348 | return -ENODEV; | ||
349 | |||
350 | if (cl->state != MEI_FILE_DISCONNECTING) | ||
351 | return 0; | ||
352 | |||
353 | cb = mei_io_cb_init(cl, NULL); | ||
354 | if (!cb) | ||
355 | return -ENOMEM; | ||
356 | |||
357 | cb->fop_type = MEI_FOP_CLOSE; | ||
358 | if (dev->mei_host_buffer_is_empty) { | ||
359 | dev->mei_host_buffer_is_empty = false; | ||
360 | if (mei_hbm_cl_disconnect_req(dev, cl)) { | ||
361 | rets = -ENODEV; | ||
362 | dev_err(&dev->pdev->dev, "failed to disconnect.\n"); | ||
363 | goto free; | ||
364 | } | ||
365 | mdelay(10); /* Wait for hardware disconnection ready */ | ||
366 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | ||
367 | } else { | ||
368 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); | ||
369 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
370 | |||
371 | } | ||
372 | mutex_unlock(&dev->device_lock); | ||
373 | |||
374 | err = wait_event_timeout(dev->wait_recvd_msg, | ||
375 | MEI_FILE_DISCONNECTED == cl->state, | ||
376 | mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); | ||
377 | |||
378 | mutex_lock(&dev->device_lock); | ||
379 | if (MEI_FILE_DISCONNECTED == cl->state) { | ||
380 | rets = 0; | ||
381 | dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); | ||
382 | } else { | ||
383 | rets = -ENODEV; | ||
384 | if (MEI_FILE_DISCONNECTED != cl->state) | ||
385 | dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); | ||
386 | |||
387 | if (err) | ||
388 | dev_dbg(&dev->pdev->dev, | ||
389 | "wait failed disconnect err=%08x\n", | ||
390 | err); | ||
391 | |||
392 | dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); | ||
393 | } | ||
394 | |||
395 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | ||
396 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | ||
397 | free: | ||
398 | mei_io_cb_free(cb); | ||
399 | return rets; | ||
400 | } | ||
401 | |||
402 | |||
403 | /** | ||
404 | * mei_other_client_is_connecting - checks if other | ||
405 | * client with the same client id is connected. | ||
406 | * | ||
407 | * @dev: the device structure | ||
408 | * @cl: private data of the file object | ||
409 | * | ||
410 | * returns 1 if other client is connected, 0 - otherwise. | ||
411 | */ | ||
412 | int mei_other_client_is_connecting(struct mei_device *dev, | ||
413 | struct mei_cl *cl) | ||
414 | { | ||
415 | struct mei_cl *cl_pos = NULL; | ||
416 | struct mei_cl *cl_next = NULL; | ||
417 | |||
418 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { | ||
419 | if ((cl_pos->state == MEI_FILE_CONNECTING) && | ||
420 | (cl_pos != cl) && | ||
421 | cl->me_client_id == cl_pos->me_client_id) | ||
422 | return 1; | ||
423 | |||
424 | } | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | /** | ||
429 | * mei_flow_ctrl_creds - checks flow_control credentials. | ||
430 | * | ||
431 | * @dev: the device structure | ||
432 | * @cl: private data of the file object | ||
433 | * | ||
434 | * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise. | ||
435 | * -ENOENT if mei_cl is not present | ||
436 | * -EINVAL if single_recv_buf == 0 | ||
437 | */ | ||
438 | int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl) | ||
439 | { | ||
440 | int i; | ||
441 | |||
442 | if (!dev->me_clients_num) | ||
443 | return 0; | ||
444 | |||
445 | if (cl->mei_flow_ctrl_creds > 0) | ||
446 | return 1; | ||
447 | |||
448 | for (i = 0; i < dev->me_clients_num; i++) { | ||
449 | struct mei_me_client *me_cl = &dev->me_clients[i]; | ||
450 | if (me_cl->client_id == cl->me_client_id) { | ||
451 | if (me_cl->mei_flow_ctrl_creds) { | ||
452 | if (WARN_ON(me_cl->props.single_recv_buf == 0)) | ||
453 | return -EINVAL; | ||
454 | return 1; | ||
455 | } else { | ||
456 | return 0; | ||
457 | } | ||
458 | } | ||
459 | } | ||
460 | return -ENOENT; | ||
461 | } | ||
462 | |||
463 | /** | ||
464 | * mei_flow_ctrl_reduce - reduces flow_control. | ||
465 | * | ||
466 | * @dev: the device structure | ||
467 | * @cl: private data of the file object | ||
468 | * @returns | ||
469 | * 0 on success | ||
470 | * -ENOENT when me client is not found | ||
471 | * -EINVAL when ctrl credits are <= 0 | ||
472 | */ | ||
473 | int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) | ||
474 | { | ||
475 | int i; | ||
476 | |||
477 | if (!dev->me_clients_num) | ||
478 | return -ENOENT; | ||
479 | |||
480 | for (i = 0; i < dev->me_clients_num; i++) { | ||
481 | struct mei_me_client *me_cl = &dev->me_clients[i]; | ||
482 | if (me_cl->client_id == cl->me_client_id) { | ||
483 | if (me_cl->props.single_recv_buf != 0) { | ||
484 | if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) | ||
485 | return -EINVAL; | ||
486 | dev->me_clients[i].mei_flow_ctrl_creds--; | ||
487 | } else { | ||
488 | if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) | ||
489 | return -EINVAL; | ||
490 | cl->mei_flow_ctrl_creds--; | ||
491 | } | ||
492 | return 0; | ||
493 | } | ||
494 | } | ||
495 | return -ENOENT; | ||
496 | } | ||
497 | |||
498 | |||
499 | |||
500 | /** | ||
158 | * mei_ioctl_connect_client - the connect to fw client IOCTL function | 501 | * mei_ioctl_connect_client - the connect to fw client IOCTL function |
159 | * | 502 | * |
160 | * @dev: the device structure | 503 | * @dev: the device structure |
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 55895fc21ff1..6c1f1f838d2b 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/mei.h> | 22 | #include <linux/mei.h> |
23 | 23 | ||
24 | #include "mei_dev.h" | 24 | #include "mei_dev.h" |
25 | #include "hbm.h" | ||
26 | #include "interface.h" | 25 | #include "interface.h" |
27 | 26 | ||
28 | const char *mei_dev_state_str(int state) | 27 | const char *mei_dev_state_str(int state) |
@@ -45,47 +44,6 @@ const char *mei_dev_state_str(int state) | |||
45 | 44 | ||
46 | 45 | ||
47 | 46 | ||
48 | /** | ||
49 | * mei_io_list_flush - removes list entry belonging to cl. | ||
50 | * | ||
51 | * @list: An instance of our list structure | ||
52 | * @cl: private data of the file object | ||
53 | */ | ||
54 | void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) | ||
55 | { | ||
56 | struct mei_cl_cb *pos; | ||
57 | struct mei_cl_cb *next; | ||
58 | |||
59 | list_for_each_entry_safe(pos, next, &list->list, list) { | ||
60 | if (pos->cl) { | ||
61 | if (mei_cl_cmp_id(cl, pos->cl)) | ||
62 | list_del(&pos->list); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | /** | ||
67 | * mei_cl_flush_queues - flushes queue lists belonging to cl. | ||
68 | * | ||
69 | * @dev: the device structure | ||
70 | * @cl: private data of the file object | ||
71 | */ | ||
72 | int mei_cl_flush_queues(struct mei_cl *cl) | ||
73 | { | ||
74 | if (!cl || !cl->dev) | ||
75 | return -EINVAL; | ||
76 | |||
77 | dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n"); | ||
78 | mei_io_list_flush(&cl->dev->read_list, cl); | ||
79 | mei_io_list_flush(&cl->dev->write_list, cl); | ||
80 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); | ||
81 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); | ||
82 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); | ||
83 | mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); | ||
84 | mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | |||
89 | 47 | ||
90 | /** | 48 | /** |
91 | * init_mei_device - allocates and initializes the mei device structure | 49 | * init_mei_device - allocates and initializes the mei device structure |
@@ -360,215 +318,5 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) | |||
360 | return ; | 318 | return ; |
361 | } | 319 | } |
362 | 320 | ||
363 | void mei_host_client_init(struct work_struct *work) | ||
364 | { | ||
365 | struct mei_device *dev = container_of(work, | ||
366 | struct mei_device, init_work); | ||
367 | struct mei_client_properties *client_props; | ||
368 | int i; | ||
369 | |||
370 | mutex_lock(&dev->device_lock); | ||
371 | |||
372 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | ||
373 | dev->open_handle_count = 0; | ||
374 | |||
375 | /* | ||
376 | * Reserving the first three client IDs | ||
377 | * 0: Reserved for MEI Bus Message communications | ||
378 | * 1: Reserved for Watchdog | ||
379 | * 2: Reserved for AMTHI | ||
380 | */ | ||
381 | bitmap_set(dev->host_clients_map, 0, 3); | ||
382 | |||
383 | for (i = 0; i < dev->me_clients_num; i++) { | ||
384 | client_props = &dev->me_clients[i].props; | ||
385 | |||
386 | if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) | ||
387 | mei_amthif_host_init(dev); | ||
388 | else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) | ||
389 | mei_wd_host_init(dev); | ||
390 | } | ||
391 | 321 | ||
392 | dev->dev_state = MEI_DEV_ENABLED; | ||
393 | |||
394 | mutex_unlock(&dev->device_lock); | ||
395 | } | ||
396 | |||
397 | |||
398 | /** | ||
399 | * mei_init_file_private - initializes private file structure. | ||
400 | * | ||
401 | * @priv: private file structure to be initialized | ||
402 | * @file: the file structure | ||
403 | */ | ||
404 | void mei_cl_init(struct mei_cl *priv, struct mei_device *dev) | ||
405 | { | ||
406 | memset(priv, 0, sizeof(struct mei_cl)); | ||
407 | init_waitqueue_head(&priv->wait); | ||
408 | init_waitqueue_head(&priv->rx_wait); | ||
409 | init_waitqueue_head(&priv->tx_wait); | ||
410 | INIT_LIST_HEAD(&priv->link); | ||
411 | priv->reading_state = MEI_IDLE; | ||
412 | priv->writing_state = MEI_IDLE; | ||
413 | priv->dev = dev; | ||
414 | } | ||
415 | |||
416 | int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid) | ||
417 | { | ||
418 | int i, res = -ENOENT; | ||
419 | |||
420 | for (i = 0; i < dev->me_clients_num; ++i) | ||
421 | if (uuid_le_cmp(*cuuid, | ||
422 | dev->me_clients[i].props.protocol_name) == 0) { | ||
423 | res = i; | ||
424 | break; | ||
425 | } | ||
426 | |||
427 | return res; | ||
428 | } | ||
429 | |||
430 | |||
431 | /** | ||
432 | * mei_me_cl_link - create link between host and me clinet and add | ||
433 | * me_cl to the list | ||
434 | * | ||
435 | * @dev: the device structure | ||
436 | * @cl: link between me and host client assocated with opened file descriptor | ||
437 | * @cuuid: uuid of ME client | ||
438 | * @client_id: id of the host client | ||
439 | * | ||
440 | * returns ME client index if ME client | ||
441 | * -EINVAL on incorrect values | ||
442 | * -ENONET if client not found | ||
443 | */ | ||
444 | int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, | ||
445 | const uuid_le *cuuid, u8 host_cl_id) | ||
446 | { | ||
447 | int i; | ||
448 | |||
449 | if (!dev || !cl || !cuuid) | ||
450 | return -EINVAL; | ||
451 | |||
452 | /* check for valid client id */ | ||
453 | i = mei_me_cl_by_uuid(dev, cuuid); | ||
454 | if (i >= 0) { | ||
455 | cl->me_client_id = dev->me_clients[i].client_id; | ||
456 | cl->state = MEI_FILE_CONNECTING; | ||
457 | cl->host_client_id = host_cl_id; | ||
458 | |||
459 | list_add_tail(&cl->link, &dev->file_list); | ||
460 | return (u8)i; | ||
461 | } | ||
462 | |||
463 | return -ENOENT; | ||
464 | } | ||
465 | /** | ||
466 | * mei_me_cl_unlink - remove me_cl from the list | ||
467 | * | ||
468 | * @dev: the device structure | ||
469 | * @host_client_id: host client id to be removed | ||
470 | */ | ||
471 | void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) | ||
472 | { | ||
473 | struct mei_cl *pos, *next; | ||
474 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { | ||
475 | if (cl->host_client_id == pos->host_client_id) { | ||
476 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", | ||
477 | pos->host_client_id, pos->me_client_id); | ||
478 | list_del_init(&pos->link); | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | } | ||
483 | |||
484 | /** | ||
485 | * mei_alloc_file_private - allocates a private file structure and sets it up. | ||
486 | * @file: the file structure | ||
487 | * | ||
488 | * returns The allocated file or NULL on failure | ||
489 | */ | ||
490 | struct mei_cl *mei_cl_allocate(struct mei_device *dev) | ||
491 | { | ||
492 | struct mei_cl *cl; | ||
493 | |||
494 | cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); | ||
495 | if (!cl) | ||
496 | return NULL; | ||
497 | |||
498 | mei_cl_init(cl, dev); | ||
499 | |||
500 | return cl; | ||
501 | } | ||
502 | |||
503 | |||
504 | |||
505 | /** | ||
506 | * mei_disconnect_host_client - sends disconnect message to fw from host client. | ||
507 | * | ||
508 | * @dev: the device structure | ||
509 | * @cl: private data of the file object | ||
510 | * | ||
511 | * Locking: called under "dev->device_lock" lock | ||
512 | * | ||
513 | * returns 0 on success, <0 on failure. | ||
514 | */ | ||
515 | int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | ||
516 | { | ||
517 | struct mei_cl_cb *cb; | ||
518 | int rets, err; | ||
519 | |||
520 | if (!dev || !cl) | ||
521 | return -ENODEV; | ||
522 | |||
523 | if (cl->state != MEI_FILE_DISCONNECTING) | ||
524 | return 0; | ||
525 | |||
526 | cb = mei_io_cb_init(cl, NULL); | ||
527 | if (!cb) | ||
528 | return -ENOMEM; | ||
529 | |||
530 | cb->fop_type = MEI_FOP_CLOSE; | ||
531 | if (dev->mei_host_buffer_is_empty) { | ||
532 | dev->mei_host_buffer_is_empty = false; | ||
533 | if (mei_hbm_cl_disconnect_req(dev, cl)) { | ||
534 | rets = -ENODEV; | ||
535 | dev_err(&dev->pdev->dev, "failed to disconnect.\n"); | ||
536 | goto free; | ||
537 | } | ||
538 | mdelay(10); /* Wait for hardware disconnection ready */ | ||
539 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | ||
540 | } else { | ||
541 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); | ||
542 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
543 | |||
544 | } | ||
545 | mutex_unlock(&dev->device_lock); | ||
546 | |||
547 | err = wait_event_timeout(dev->wait_recvd_msg, | ||
548 | MEI_FILE_DISCONNECTED == cl->state, | ||
549 | mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); | ||
550 | |||
551 | mutex_lock(&dev->device_lock); | ||
552 | if (MEI_FILE_DISCONNECTED == cl->state) { | ||
553 | rets = 0; | ||
554 | dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); | ||
555 | } else { | ||
556 | rets = -ENODEV; | ||
557 | if (MEI_FILE_DISCONNECTED != cl->state) | ||
558 | dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); | ||
559 | |||
560 | if (err) | ||
561 | dev_dbg(&dev->pdev->dev, | ||
562 | "wait failed disconnect err=%08x\n", | ||
563 | err); | ||
564 | |||
565 | dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); | ||
566 | } | ||
567 | |||
568 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | ||
569 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | ||
570 | free: | ||
571 | mei_io_cb_free(cb); | ||
572 | return rets; | ||
573 | } | ||
574 | 322 | ||
diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c index 155bd7efe4e5..3cb0cff01285 100644 --- a/drivers/misc/mei/interface.c +++ b/drivers/misc/mei/interface.c | |||
@@ -297,99 +297,3 @@ void mei_read_slots(struct mei_device *dev, unsigned char *buffer, | |||
297 | mei_hcsr_set(dev); | 297 | mei_hcsr_set(dev); |
298 | } | 298 | } |
299 | 299 | ||
300 | /** | ||
301 | * mei_flow_ctrl_creds - checks flow_control credentials. | ||
302 | * | ||
303 | * @dev: the device structure | ||
304 | * @cl: private data of the file object | ||
305 | * | ||
306 | * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise. | ||
307 | * -ENOENT if mei_cl is not present | ||
308 | * -EINVAL if single_recv_buf == 0 | ||
309 | */ | ||
310 | int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl) | ||
311 | { | ||
312 | int i; | ||
313 | |||
314 | if (!dev->me_clients_num) | ||
315 | return 0; | ||
316 | |||
317 | if (cl->mei_flow_ctrl_creds > 0) | ||
318 | return 1; | ||
319 | |||
320 | for (i = 0; i < dev->me_clients_num; i++) { | ||
321 | struct mei_me_client *me_cl = &dev->me_clients[i]; | ||
322 | if (me_cl->client_id == cl->me_client_id) { | ||
323 | if (me_cl->mei_flow_ctrl_creds) { | ||
324 | if (WARN_ON(me_cl->props.single_recv_buf == 0)) | ||
325 | return -EINVAL; | ||
326 | return 1; | ||
327 | } else { | ||
328 | return 0; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | return -ENOENT; | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * mei_flow_ctrl_reduce - reduces flow_control. | ||
337 | * | ||
338 | * @dev: the device structure | ||
339 | * @cl: private data of the file object | ||
340 | * @returns | ||
341 | * 0 on success | ||
342 | * -ENOENT when me client is not found | ||
343 | * -EINVAL when ctrl credits are <= 0 | ||
344 | */ | ||
345 | int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) | ||
346 | { | ||
347 | int i; | ||
348 | |||
349 | if (!dev->me_clients_num) | ||
350 | return -ENOENT; | ||
351 | |||
352 | for (i = 0; i < dev->me_clients_num; i++) { | ||
353 | struct mei_me_client *me_cl = &dev->me_clients[i]; | ||
354 | if (me_cl->client_id == cl->me_client_id) { | ||
355 | if (me_cl->props.single_recv_buf != 0) { | ||
356 | if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) | ||
357 | return -EINVAL; | ||
358 | dev->me_clients[i].mei_flow_ctrl_creds--; | ||
359 | } else { | ||
360 | if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) | ||
361 | return -EINVAL; | ||
362 | cl->mei_flow_ctrl_creds--; | ||
363 | } | ||
364 | return 0; | ||
365 | } | ||
366 | } | ||
367 | return -ENOENT; | ||
368 | } | ||
369 | |||
370 | |||
371 | /** | ||
372 | * mei_other_client_is_connecting - checks if other | ||
373 | * client with the same client id is connected. | ||
374 | * | ||
375 | * @dev: the device structure | ||
376 | * @cl: private data of the file object | ||
377 | * | ||
378 | * returns 1 if other client is connected, 0 - otherwise. | ||
379 | */ | ||
380 | int mei_other_client_is_connecting(struct mei_device *dev, | ||
381 | struct mei_cl *cl) | ||
382 | { | ||
383 | struct mei_cl *cl_pos = NULL; | ||
384 | struct mei_cl *cl_next = NULL; | ||
385 | |||
386 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { | ||
387 | if ((cl_pos->state == MEI_FILE_CONNECTING) && | ||
388 | (cl_pos != cl) && | ||
389 | cl->me_client_id == cl_pos->me_client_id) | ||
390 | return 1; | ||
391 | |||
392 | } | ||
393 | return 0; | ||
394 | } | ||
395 | |||