microblaze: Correspond CONFIG...PCMP in Makefile/Kconfig
[linux-2.6/mini2440.git] / drivers / staging / heci / heci_init.c
bloba8a0da910cfbbe173f446bcca3a24bf186b6d0b1
1 /*
2 * Part of Intel(R) Manageability Engine Interface Linux driver
4 * Copyright (c) 2003 - 2008 Intel Corp.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer,
12 * without modification.
13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14 * substantially similar to the "NO WARRANTY" disclaimer below
15 * ("Disclaimer") and any redistribution must be conditioned upon
16 * including a substantially similar Disclaimer requirement for further
17 * binary redistribution.
18 * 3. Neither the names of the above-listed copyright holders nor the names
19 * of any contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * Alternatively, this software may be distributed under the terms of the
23 * GNU General Public License ("GPL") version 2 as published by the Free
24 * Software Foundation.
26 * NO WARRANTY
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
36 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGES.
41 #include <linux/module.h>
42 #include <linux/pci.h>
43 #include <linux/reboot.h>
44 #include <linux/poll.h>
45 #include <linux/init.h>
46 #include <linux/kdev_t.h>
47 #include <linux/moduleparam.h>
48 #include <linux/wait.h>
49 #include <linux/delay.h>
50 #include <linux/kthread.h>
52 #include "heci_data_structures.h"
53 #include "heci_interface.h"
54 #include "heci.h"
57 const __u8 heci_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
58 const __u8 heci_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
60 const __u8 heci_wd_state_independence_msg[3][4] = {
61 {0x05, 0x02, 0x51, 0x10},
62 {0x05, 0x02, 0x52, 0x10},
63 {0x07, 0x02, 0x01, 0x10}
66 static const struct guid heci_asf_guid = {
67 0x75B30CD6, 0xA29E, 0x4AF7,
68 {0xA7, 0x12, 0xE6, 0x17, 0x43, 0x93, 0xC8, 0xA6}
70 const struct guid heci_wd_guid = {
71 0x05B79A6F, 0x4628, 0x4D7F,
72 {0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB}
74 const struct guid heci_pthi_guid = {
75 0x12f80028, 0xb4b7, 0x4b2d,
76 {0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c}
81 * heci init function prototypes
83 static void heci_check_asf_mode(struct iamt_heci_device *dev);
84 static int host_start_message(struct iamt_heci_device *dev);
85 static int host_enum_clients_message(struct iamt_heci_device *dev);
86 static int allocate_me_clients_storage(struct iamt_heci_device *dev);
87 static void host_init_wd(struct iamt_heci_device *dev);
88 static void host_init_iamthif(struct iamt_heci_device *dev);
89 static int heci_wait_event_int_timeout(struct iamt_heci_device *dev,
90 long timeout);
93 /**
94 * heci_initialize_list - Sets up a queue list.
96 * @list: An instance of our list structure
97 * @dev: Device object for our driver
99 void heci_initialize_list(struct io_heci_list *list,
100 struct iamt_heci_device *dev)
102 /* initialize our queue list */
103 INIT_LIST_HEAD(&list->heci_cb.cb_list);
104 list->status = 0;
105 list->device_extension = dev;
109 * heci_flush_queues - flush our queues list belong to file_ext.
111 * @dev: Device object for our driver
112 * @file_ext: private data of the file object
114 void heci_flush_queues(struct iamt_heci_device *dev,
115 struct heci_file_private *file_ext)
117 int i;
119 if (!dev || !file_ext)
120 return;
122 /* flush our queue list belong to file_ext */
123 for (i = 0; i < HECI_IO_LISTS_NUMBER; i++) {
124 DBG("remove list entry belong to file_ext\n");
125 heci_flush_list(dev->io_list_array[i], file_ext);
131 * heci_flush_list - remove list entry belong to file_ext.
133 * @list: An instance of our list structure
134 * @file_ext: private data of the file object
136 void heci_flush_list(struct io_heci_list *list,
137 struct heci_file_private *file_ext)
139 struct heci_file_private *file_ext_tmp;
140 struct heci_cb_private *priv_cb_pos = NULL;
141 struct heci_cb_private *priv_cb_next = NULL;
143 if (!list || !file_ext)
144 return;
146 if (list->status != 0)
147 return;
149 if (list_empty(&list->heci_cb.cb_list))
150 return;
152 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
153 &list->heci_cb.cb_list, cb_list) {
154 if (priv_cb_pos) {
155 file_ext_tmp = (struct heci_file_private *)
156 priv_cb_pos->file_private;
157 if (file_ext_tmp) {
158 if (heci_fe_same_id(file_ext, file_ext_tmp))
159 list_del(&priv_cb_pos->cb_list);
166 * heci_reset_iamthif_params - initializes heci device iamthif
168 * @dev: The heci device structure
170 static void heci_reset_iamthif_params(struct iamt_heci_device *dev)
172 /* reset iamthif parameters. */
173 dev->iamthif_current_cb = NULL;
174 dev->iamthif_msg_buf_size = 0;
175 dev->iamthif_msg_buf_index = 0;
176 dev->iamthif_canceled = 0;
177 dev->iamthif_file_ext.file = NULL;
178 dev->iamthif_ioctl = 0;
179 dev->iamthif_state = HECI_IAMTHIF_IDLE;
180 dev->iamthif_timer = 0;
184 * init_heci_device - allocates and initializes the heci device structure
186 * @pdev: The pci device structure
188 * returns The heci_device_device pointer on success, NULL on failure.
190 struct iamt_heci_device *init_heci_device(struct pci_dev *pdev)
192 int i;
193 struct iamt_heci_device *dev;
195 dev = kzalloc(sizeof(struct iamt_heci_device), GFP_KERNEL);
196 if (!dev)
197 return NULL;
199 /* setup our list array */
200 dev->io_list_array[0] = &dev->read_list;
201 dev->io_list_array[1] = &dev->write_list;
202 dev->io_list_array[2] = &dev->write_waiting_list;
203 dev->io_list_array[3] = &dev->ctrl_wr_list;
204 dev->io_list_array[4] = &dev->ctrl_rd_list;
205 dev->io_list_array[5] = &dev->pthi_cmd_list;
206 dev->io_list_array[6] = &dev->pthi_read_complete_list;
207 INIT_LIST_HEAD(&dev->file_list);
208 INIT_LIST_HEAD(&dev->wd_file_ext.link);
209 INIT_LIST_HEAD(&dev->iamthif_file_ext.link);
210 spin_lock_init(&dev->device_lock);
211 init_waitqueue_head(&dev->wait_recvd_msg);
212 init_waitqueue_head(&dev->wait_stop_wd);
213 dev->heci_state = HECI_INITIALIZING;
214 dev->iamthif_state = HECI_IAMTHIF_IDLE;
216 /* init work for schedule work */
217 INIT_WORK(&dev->work, NULL);
218 for (i = 0; i < HECI_IO_LISTS_NUMBER; i++)
219 heci_initialize_list(dev->io_list_array[i], dev);
220 dev->pdev = pdev;
221 return dev;
227 static int heci_wait_event_int_timeout(struct iamt_heci_device *dev,
228 long timeout)
230 return wait_event_interruptible_timeout(dev->wait_recvd_msg,
231 (dev->recvd_msg), timeout);
235 * heci_hw_init - init host and fw to start work.
237 * @dev: Device object for our driver
239 * returns 0 on success, <0 on failure.
241 int heci_hw_init(struct iamt_heci_device *dev)
243 int err = 0;
245 dev->host_hw_state = read_heci_register(dev, H_CSR);
246 dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
247 DBG("host_hw_state = 0x%08x, mestate = 0x%08x.\n",
248 dev->host_hw_state, dev->me_hw_state);
250 if ((dev->host_hw_state & H_IS) == H_IS) {
251 /* acknowledge interrupt and stop interupts */
252 heci_set_csr_register(dev);
254 dev->recvd_msg = 0;
255 DBG("reset in start the heci device.\n");
257 heci_reset(dev, 1);
259 DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
260 dev->host_hw_state, dev->me_hw_state);
262 /* wait for ME to turn on ME_RDY */
263 if (!dev->recvd_msg)
264 err = heci_wait_event_int_timeout(dev, HECI_INTEROP_TIMEOUT);
266 if (!err && !dev->recvd_msg) {
267 dev->heci_state = HECI_DISABLED;
268 DBG("wait_event_interruptible_timeout failed"
269 "on wait for ME to turn on ME_RDY.\n");
270 return -ENODEV;
271 } else {
272 if (!(((dev->host_hw_state & H_RDY) == H_RDY)
273 && ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
274 dev->heci_state = HECI_DISABLED;
275 DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
276 dev->host_hw_state,
277 dev->me_hw_state);
279 if (!(dev->host_hw_state & H_RDY) != H_RDY)
280 DBG("host turn off H_RDY.\n");
282 if (!(dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
283 DBG("ME turn off ME_RDY.\n");
285 printk(KERN_ERR
286 "heci: link layer initialization failed.\n");
287 return -ENODEV;
290 dev->recvd_msg = 0;
291 DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
292 dev->host_hw_state, dev->me_hw_state);
293 DBG("ME turn on ME_RDY and host turn on H_RDY.\n");
294 printk(KERN_INFO "heci: link layer has been established.\n");
295 return 0;
299 * heci_hw_reset - reset fw via heci csr register.
301 * @dev: Device object for our driver
302 * @interrupts: if interrupt should be enable after reset.
304 static void heci_hw_reset(struct iamt_heci_device *dev, int interrupts)
306 dev->host_hw_state |= (H_RST | H_IG);
308 if (interrupts)
309 heci_csr_enable_interrupts(dev);
310 else
311 heci_csr_disable_interrupts(dev);
313 BUG_ON((dev->host_hw_state & H_RST) != H_RST);
314 BUG_ON((dev->host_hw_state & H_RDY) != 0);
318 * heci_reset - reset host and fw.
320 * @dev: Device object for our driver
321 * @interrupts: if interrupt should be enable after reset.
323 void heci_reset(struct iamt_heci_device *dev, int interrupts)
325 struct heci_file_private *file_pos = NULL;
326 struct heci_file_private *file_next = NULL;
327 struct heci_cb_private *priv_cb_pos = NULL;
328 struct heci_cb_private *priv_cb_next = NULL;
329 int unexpected = 0;
331 if (dev->heci_state == HECI_RECOVERING_FROM_RESET) {
332 dev->need_reset = 1;
333 return;
336 if (dev->heci_state != HECI_INITIALIZING &&
337 dev->heci_state != HECI_DISABLED &&
338 dev->heci_state != HECI_POWER_DOWN &&
339 dev->heci_state != HECI_POWER_UP)
340 unexpected = 1;
342 if (dev->reinit_tsk != NULL) {
343 kthread_stop(dev->reinit_tsk);
344 dev->reinit_tsk = NULL;
347 dev->host_hw_state = read_heci_register(dev, H_CSR);
349 DBG("before reset host_hw_state = 0x%08x.\n",
350 dev->host_hw_state);
352 heci_hw_reset(dev, interrupts);
354 dev->host_hw_state &= ~H_RST;
355 dev->host_hw_state |= H_IG;
357 write_heci_register(dev, H_CSR, dev->host_hw_state);
359 DBG("currently saved host_hw_state = 0x%08x.\n",
360 dev->host_hw_state);
362 dev->need_reset = 0;
364 if (dev->heci_state != HECI_INITIALIZING) {
365 if ((dev->heci_state != HECI_DISABLED) &&
366 (dev->heci_state != HECI_POWER_DOWN))
367 dev->heci_state = HECI_RESETING;
369 list_for_each_entry_safe(file_pos,
370 file_next, &dev->file_list, link) {
371 file_pos->state = HECI_FILE_DISCONNECTED;
372 file_pos->flow_ctrl_creds = 0;
373 file_pos->read_cb = NULL;
374 file_pos->timer_count = 0;
376 /* remove entry if already in list */
377 DBG("list del iamthif and wd file list.\n");
378 heci_remove_client_from_file_list(dev,
379 dev->wd_file_ext.host_client_id);
381 heci_remove_client_from_file_list(dev,
382 dev->iamthif_file_ext.host_client_id);
384 heci_reset_iamthif_params(dev);
385 dev->wd_due_counter = 0;
386 dev->extra_write_index = 0;
389 dev->num_heci_me_clients = 0;
390 dev->rd_msg_hdr = 0;
391 dev->stop = 0;
392 dev->wd_pending = 0;
394 /* update the state of the registers after reset */
395 dev->host_hw_state = read_heci_register(dev, H_CSR);
396 dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
398 DBG("after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
399 dev->host_hw_state, dev->me_hw_state);
401 if (unexpected)
402 printk(KERN_WARNING "heci: unexpected reset.\n");
404 /* Wake up all readings so they can be interrupted */
405 list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) {
406 if (&file_pos->rx_wait &&
407 waitqueue_active(&file_pos->rx_wait)) {
408 printk(KERN_INFO "heci: Waking up client!\n");
409 wake_up_interruptible(&file_pos->rx_wait);
412 /* remove all waiting requests */
413 if (dev->write_list.status == 0 &&
414 !list_empty(&dev->write_list.heci_cb.cb_list)) {
415 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
416 &dev->write_list.heci_cb.cb_list, cb_list) {
417 if (priv_cb_pos) {
418 list_del(&priv_cb_pos->cb_list);
419 heci_free_cb_private(priv_cb_pos);
426 * heci_initialize_clients - heci communication initialization.
428 * @dev: Device object for our driver
430 int heci_initialize_clients(struct iamt_heci_device *dev)
432 int status;
434 msleep(100); /* FW needs time to be ready to talk with us */
435 DBG("link is established start sending messages.\n");
436 /* link is established start sending messages. */
437 status = host_start_message(dev);
438 if (status != 0) {
439 spin_lock_bh(&dev->device_lock);
440 dev->heci_state = HECI_DISABLED;
441 spin_unlock_bh(&dev->device_lock);
442 DBG("start sending messages failed.\n");
443 return status;
446 /* enumerate clients */
447 status = host_enum_clients_message(dev);
448 if (status != 0) {
449 spin_lock_bh(&dev->device_lock);
450 dev->heci_state = HECI_DISABLED;
451 spin_unlock_bh(&dev->device_lock);
452 DBG("enum clients failed.\n");
453 return status;
455 /* allocate storage for ME clients representation */
456 status = allocate_me_clients_storage(dev);
457 if (status != 0) {
458 spin_lock_bh(&dev->device_lock);
459 dev->num_heci_me_clients = 0;
460 dev->heci_state = HECI_DISABLED;
461 spin_unlock_bh(&dev->device_lock);
462 DBG("allocate clients failed.\n");
463 return status;
466 heci_check_asf_mode(dev);
467 /*heci initialization wd */
468 host_init_wd(dev);
469 /*heci initialization iamthif client */
470 host_init_iamthif(dev);
472 spin_lock_bh(&dev->device_lock);
473 if (dev->need_reset) {
474 dev->need_reset = 0;
475 dev->heci_state = HECI_DISABLED;
476 spin_unlock_bh(&dev->device_lock);
477 return -ENODEV;
480 memset(dev->heci_host_clients, 0, sizeof(dev->heci_host_clients));
481 dev->open_handle_count = 0;
482 dev->heci_host_clients[0] |= 7;
483 dev->current_host_client_id = 3;
484 dev->heci_state = HECI_ENABLED;
485 spin_unlock_bh(&dev->device_lock);
486 DBG("initialization heci clients successful.\n");
487 return 0;
491 * heci_task_initialize_clients - heci reinitialization task
493 * @data: Device object for our driver
495 int heci_task_initialize_clients(void *data)
497 int ret;
498 struct iamt_heci_device *dev = (struct iamt_heci_device *) data;
500 spin_lock_bh(&dev->device_lock);
501 if (dev->reinit_tsk != NULL) {
502 spin_unlock_bh(&dev->device_lock);
503 DBG("reinit task already started.\n");
504 return 0;
506 dev->reinit_tsk = current;
507 current->flags |= PF_NOFREEZE;
508 spin_unlock_bh(&dev->device_lock);
510 ret = heci_initialize_clients(dev);
512 spin_lock_bh(&dev->device_lock);
513 dev->reinit_tsk = NULL;
514 spin_unlock_bh(&dev->device_lock);
516 return ret;
520 * host_start_message - heci host send start message.
522 * @dev: Device object for our driver
524 * returns 0 on success, <0 on failure.
526 static int host_start_message(struct iamt_heci_device *dev)
528 long timeout = 60; /* 60 second */
530 struct heci_msg_hdr *heci_hdr;
531 struct hbm_host_version_request *host_start_req;
532 struct hbm_host_stop_request *host_stop_req;
533 int err = 0;
535 /* host start message */
536 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
537 heci_hdr->host_addr = 0;
538 heci_hdr->me_addr = 0;
539 heci_hdr->length = sizeof(struct hbm_host_version_request);
540 heci_hdr->msg_complete = 1;
541 heci_hdr->reserved = 0;
543 host_start_req =
544 (struct hbm_host_version_request *) &dev->wr_msg_buf[1];
545 memset(host_start_req, 0, sizeof(struct hbm_host_version_request));
546 host_start_req->cmd.cmd = HOST_START_REQ_CMD;
547 host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
548 host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
549 dev->recvd_msg = 0;
550 if (!heci_write_message(dev, heci_hdr,
551 (unsigned char *) (host_start_req),
552 heci_hdr->length)) {
553 DBG("send version to fw fail.\n");
554 return -ENODEV;
556 DBG("call wait_event_interruptible_timeout for response message.\n");
557 /* wait for response */
558 err = heci_wait_event_int_timeout(dev, timeout * HZ);
559 if (!err && !dev->recvd_msg) {
560 DBG("wait_timeout failed on host start response message.\n");
561 return -ENODEV;
563 dev->recvd_msg = 0;
564 DBG("wait_timeout successful on host start response message.\n");
565 if ((dev->version.major_version != HBM_MAJOR_VERSION) ||
566 (dev->version.minor_version != HBM_MINOR_VERSION)) {
567 /* send stop message */
568 heci_hdr->host_addr = 0;
569 heci_hdr->me_addr = 0;
570 heci_hdr->length = sizeof(struct hbm_host_stop_request);
571 heci_hdr->msg_complete = 1;
572 heci_hdr->reserved = 0;
574 host_stop_req =
575 (struct hbm_host_stop_request *) &dev->wr_msg_buf[1];
577 memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
578 host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
579 host_stop_req->reason = DRIVER_STOP_REQUEST;
580 heci_write_message(dev, heci_hdr,
581 (unsigned char *) (host_stop_req),
582 heci_hdr->length);
583 DBG("version mismatch.\n");
584 return -ENODEV;
587 return 0;
591 * host_enum_clients_message - host send enumeration client request message.
593 * @dev: Device object for our driver
595 * returns 0 on success, <0 on failure.
597 static int host_enum_clients_message(struct iamt_heci_device *dev)
599 long timeout = 5; /*5 second */
600 struct heci_msg_hdr *heci_hdr;
601 struct hbm_host_enum_request *host_enum_req;
602 int err = 0;
603 int i, j;
605 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
606 /* enumerate clients */
607 heci_hdr->host_addr = 0;
608 heci_hdr->me_addr = 0;
609 heci_hdr->length = sizeof(struct hbm_host_enum_request);
610 heci_hdr->msg_complete = 1;
611 heci_hdr->reserved = 0;
613 host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
614 memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request));
615 host_enum_req->cmd.cmd = HOST_ENUM_REQ_CMD;
616 if (!heci_write_message(dev, heci_hdr,
617 (unsigned char *) (host_enum_req),
618 heci_hdr->length)) {
619 DBG("send enumeration request failed.\n");
620 return -ENODEV;
622 /* wait for response */
623 dev->recvd_msg = 0;
624 err = heci_wait_event_int_timeout(dev, timeout * HZ);
625 if (!err && !dev->recvd_msg) {
626 DBG("wait_event_interruptible_timeout failed "
627 "on enumeration clients response message.\n");
628 return -ENODEV;
630 dev->recvd_msg = 0;
632 spin_lock_bh(&dev->device_lock);
633 /* count how many ME clients we have */
634 for (i = 0; i < sizeof(dev->heci_me_clients); i++) {
635 for (j = 0; j < 8; j++) {
636 if ((dev->heci_me_clients[i] & (1 << j)) != 0)
637 dev->num_heci_me_clients++;
641 spin_unlock_bh(&dev->device_lock);
643 return 0;
647 * host_client_properties - reads properties for client
649 * @dev: Device object for our driver
650 * @idx: client index in me client array
651 * @client_id: id of the client
653 * returns 0 on success, <0 on failure.
655 static int host_client_properties(struct iamt_heci_device *dev,
656 struct heci_me_client *client)
658 struct heci_msg_hdr *heci_hdr;
659 struct hbm_props_request *host_cli_req;
660 int err;
662 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
663 heci_hdr->host_addr = 0;
664 heci_hdr->me_addr = 0;
665 heci_hdr->length = sizeof(struct hbm_props_request);
666 heci_hdr->msg_complete = 1;
667 heci_hdr->reserved = 0;
669 host_cli_req = (struct hbm_props_request *) &dev->wr_msg_buf[1];
670 memset(host_cli_req, 0, sizeof(struct hbm_props_request));
671 host_cli_req->cmd.cmd = HOST_CLIENT_PROPERTEIS_REQ_CMD;
672 host_cli_req->address = client->client_id;
673 if (!heci_write_message(dev, heci_hdr,
674 (unsigned char *) (host_cli_req),
675 heci_hdr->length)) {
676 DBG("send props request failed.\n");
677 return -ENODEV;
679 /* wait for response */
680 dev->recvd_msg = 0;
681 err = heci_wait_event_int_timeout(dev, 10 * HZ);
682 if (!err && !dev->recvd_msg) {
683 DBG("wait failed on props resp msg.\n");
684 return -ENODEV;
686 dev->recvd_msg = 0;
687 return 0;
691 * allocate_me_clients_storage - allocate storage for me clients
693 * @dev: Device object for our driver
695 * returns 0 on success, <0 on failure.
697 static int allocate_me_clients_storage(struct iamt_heci_device *dev)
699 struct heci_me_client *clients;
700 struct heci_me_client *client;
701 __u8 num, i, j;
702 int err;
704 if (dev->num_heci_me_clients <= 0)
705 return 0;
707 spin_lock_bh(&dev->device_lock);
708 kfree(dev->me_clients);
709 dev->me_clients = NULL;
710 spin_unlock_bh(&dev->device_lock);
712 /* allocate storage for ME clients representation */
713 clients = kcalloc(dev->num_heci_me_clients,
714 sizeof(struct heci_me_client), GFP_KERNEL);
715 if (!clients) {
716 DBG("memory allocation for ME clients failed.\n");
717 return -ENOMEM;
720 spin_lock_bh(&dev->device_lock);
721 dev->me_clients = clients;
722 spin_unlock_bh(&dev->device_lock);
724 num = 0;
725 for (i = 0; i < sizeof(dev->heci_me_clients); i++) {
726 for (j = 0; j < 8; j++) {
727 if ((dev->heci_me_clients[i] & (1 << j)) != 0) {
728 client = &dev->me_clients[num];
729 client->client_id = (i * 8) + j;
730 client->flow_ctrl_creds = 0;
731 err = host_client_properties(dev, client);
732 if (err != 0) {
733 spin_lock_bh(&dev->device_lock);
734 kfree(dev->me_clients);
735 dev->me_clients = NULL;
736 spin_unlock_bh(&dev->device_lock);
737 return err;
739 num++;
744 return 0;
748 * heci_init_file_private - initializes private file structure.
750 * @priv: private file structure to be initialized
751 * @file: the file structure
753 static void heci_init_file_private(struct heci_file_private *priv,
754 struct file *file)
756 memset(priv, 0, sizeof(struct heci_file_private));
757 spin_lock_init(&priv->file_lock);
758 spin_lock_init(&priv->read_io_lock);
759 spin_lock_init(&priv->write_io_lock);
760 init_waitqueue_head(&priv->wait);
761 init_waitqueue_head(&priv->rx_wait);
762 DBG("priv->rx_wait =%p\n", &priv->rx_wait);
763 init_waitqueue_head(&priv->tx_wait);
764 INIT_LIST_HEAD(&priv->link);
765 priv->reading_state = HECI_IDLE;
766 priv->writing_state = HECI_IDLE;
770 * heci_find_me_client - search for ME client guid
771 * sets client_id in heci_file_private if found
772 * @dev: Device object for our driver
773 * @priv: private file structure to set client_id in
774 * @cguid: searched guid of ME client
775 * @client_id: id of host client to be set in file private structure
777 * returns ME client index
779 static __u8 heci_find_me_client(struct iamt_heci_device *dev,
780 struct heci_file_private *priv,
781 const struct guid *cguid, __u8 client_id)
783 __u8 i;
785 if ((dev == NULL) || (priv == NULL) || (cguid == NULL))
786 return 0;
788 for (i = 0; i < dev->num_heci_me_clients; i++) {
789 if (memcmp(cguid,
790 &dev->me_clients[i].props.protocol_name,
791 sizeof(struct guid)) == 0) {
792 priv->me_client_id = dev->me_clients[i].client_id;
793 priv->state = HECI_FILE_CONNECTING;
794 priv->host_client_id = client_id;
796 list_add_tail(&priv->link, &dev->file_list);
797 return i;
800 return 0;
804 * heci_check_asf_mode - check for ASF client
806 * @dev: Device object for our driver
808 static void heci_check_asf_mode(struct iamt_heci_device *dev)
810 __u8 i;
812 spin_lock_bh(&dev->device_lock);
813 dev->asf_mode = 0;
814 /* find ME ASF client - otherwise assume AMT mode */
815 DBG("find ME ASF client - otherwise assume AMT mode.\n");
816 for (i = 0; i < dev->num_heci_me_clients; i++) {
817 if (memcmp(&heci_asf_guid,
818 &dev->me_clients[i].props.protocol_name,
819 sizeof(struct guid)) == 0) {
820 dev->asf_mode = 1;
821 spin_unlock_bh(&dev->device_lock);
822 DBG("found ME ASF client.\n");
823 return;
826 spin_unlock_bh(&dev->device_lock);
827 DBG("assume AMT mode.\n");
831 * heci_connect_me_client - connect ME client
832 * @dev: Device object for our driver
833 * @priv: private file structure
834 * @timeout: connect timeout in seconds
836 * returns 1 - if connected, 0 - if not
838 static __u8 heci_connect_me_client(struct iamt_heci_device *dev,
839 struct heci_file_private *priv,
840 long timeout)
842 int err = 0;
844 if ((dev == NULL) || (priv == NULL))
845 return 0;
847 if (!heci_connect(dev, priv)) {
848 DBG("failed to call heci_connect for client_id=%d.\n",
849 priv->host_client_id);
850 spin_lock_bh(&dev->device_lock);
851 heci_remove_client_from_file_list(dev, priv->host_client_id);
852 priv->state = HECI_FILE_DISCONNECTED;
853 spin_unlock_bh(&dev->device_lock);
854 return 0;
857 err = wait_event_timeout(dev->wait_recvd_msg,
858 (HECI_FILE_CONNECTED == priv->state ||
859 HECI_FILE_DISCONNECTED == priv->state),
860 timeout * HZ);
861 if (HECI_FILE_CONNECTED != priv->state) {
862 spin_lock_bh(&dev->device_lock);
863 heci_remove_client_from_file_list(dev, priv->host_client_id);
864 DBG("failed to connect client_id=%d state=%d.\n",
865 priv->host_client_id, priv->state);
866 if (err)
867 DBG("failed connect err=%08x\n", err);
868 priv->state = HECI_FILE_DISCONNECTED;
869 spin_unlock_bh(&dev->device_lock);
870 return 0;
872 DBG("successfully connected client_id=%d.\n",
873 priv->host_client_id);
874 return 1;
878 * host_init_wd - heci initialization wd.
880 * @dev: Device object for our driver
882 static void host_init_wd(struct iamt_heci_device *dev)
884 spin_lock_bh(&dev->device_lock);
886 heci_init_file_private(&dev->wd_file_ext, NULL);
888 /* look for WD client and connect to it */
889 dev->wd_file_ext.state = HECI_FILE_DISCONNECTED;
890 dev->wd_timeout = 0;
892 if (dev->asf_mode) {
893 memcpy(dev->wd_data, heci_stop_wd_params, HECI_WD_PARAMS_SIZE);
894 } else {
895 /* AMT mode */
896 dev->wd_timeout = AMT_WD_VALUE;
897 DBG("dev->wd_timeout=%d.\n", dev->wd_timeout);
898 memcpy(dev->wd_data, heci_start_wd_params, HECI_WD_PARAMS_SIZE);
899 memcpy(dev->wd_data + HECI_WD_PARAMS_SIZE,
900 &dev->wd_timeout, sizeof(__u16));
903 /* find ME WD client */
904 heci_find_me_client(dev, &dev->wd_file_ext,
905 &heci_wd_guid, HECI_WD_HOST_CLIENT_ID);
906 spin_unlock_bh(&dev->device_lock);
908 DBG("check wd_file_ext\n");
909 if (HECI_FILE_CONNECTING == dev->wd_file_ext.state) {
910 if (heci_connect_me_client(dev, &dev->wd_file_ext, 15) == 1) {
911 DBG("dev->wd_timeout=%d.\n", dev->wd_timeout);
912 if (dev->wd_timeout != 0)
913 dev->wd_due_counter = 1;
914 else
915 dev->wd_due_counter = 0;
916 DBG("successfully connected to WD client.\n");
918 } else
919 DBG("failed to find WD client.\n");
922 spin_lock_bh(&dev->device_lock);
923 dev->wd_timer.function = &heci_wd_timer;
924 dev->wd_timer.data = (unsigned long) dev;
925 spin_unlock_bh(&dev->device_lock);
930 * host_init_iamthif - heci initialization iamthif client.
932 * @dev: Device object for our driver
935 static void host_init_iamthif(struct iamt_heci_device *dev)
937 __u8 i;
939 spin_lock_bh(&dev->device_lock);
941 heci_init_file_private(&dev->iamthif_file_ext, NULL);
942 dev->iamthif_file_ext.state = HECI_FILE_DISCONNECTED;
944 /* find ME PTHI client */
945 i = heci_find_me_client(dev, &dev->iamthif_file_ext,
946 &heci_pthi_guid, HECI_IAMTHIF_HOST_CLIENT_ID);
947 if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTING) {
948 DBG("failed to find iamthif client.\n");
949 spin_unlock_bh(&dev->device_lock);
950 return;
953 BUG_ON(dev->me_clients[i].props.max_msg_length != IAMTHIF_MTU);
955 spin_unlock_bh(&dev->device_lock);
956 if (heci_connect_me_client(dev, &dev->iamthif_file_ext, 15) == 1) {
957 DBG("connected to iamthif client.\n");
958 dev->iamthif_state = HECI_IAMTHIF_IDLE;
963 * heci_alloc_file_private - allocates a private file structure and set it up.
964 * @file: the file structure
966 * returns The allocated file or NULL on failure
968 struct heci_file_private *heci_alloc_file_private(struct file *file)
970 struct heci_file_private *priv;
972 priv = kmalloc(sizeof(struct heci_file_private), GFP_KERNEL);
973 if (!priv)
974 return NULL;
976 heci_init_file_private(priv, file);
978 return priv;
984 * heci_disconnect_host_client - send disconnect message to fw from host client.
986 * @dev: Device object for our driver
987 * @file_ext: private data of the file object
989 * returns 0 on success, <0 on failure.
991 int heci_disconnect_host_client(struct iamt_heci_device *dev,
992 struct heci_file_private *file_ext)
994 int rets, err;
995 long timeout = 15; /* 15 seconds */
996 struct heci_cb_private *priv_cb;
998 if ((!dev) || (!file_ext))
999 return -ENODEV;
1001 if (file_ext->state != HECI_FILE_DISCONNECTING)
1002 return 0;
1004 priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
1005 if (!priv_cb)
1006 return -ENOMEM;
1008 INIT_LIST_HEAD(&priv_cb->cb_list);
1009 priv_cb->file_private = file_ext;
1010 priv_cb->major_file_operations = HECI_CLOSE;
1011 spin_lock_bh(&dev->device_lock);
1012 if (dev->host_buffer_is_empty) {
1013 dev->host_buffer_is_empty = 0;
1014 if (heci_disconnect(dev, file_ext)) {
1015 list_add_tail(&priv_cb->cb_list,
1016 &dev->ctrl_rd_list.heci_cb.cb_list);
1017 } else {
1018 spin_unlock_bh(&dev->device_lock);
1019 rets = -ENODEV;
1020 DBG("failed to call heci_disconnect.\n");
1021 goto free;
1023 } else {
1024 DBG("add disconnect cb to control write list\n");
1025 list_add_tail(&priv_cb->cb_list,
1026 &dev->ctrl_wr_list.heci_cb.cb_list);
1028 spin_unlock_bh(&dev->device_lock);
1030 err = wait_event_timeout(dev->wait_recvd_msg,
1031 (HECI_FILE_DISCONNECTED == file_ext->state),
1032 timeout * HZ);
1033 if (HECI_FILE_DISCONNECTED == file_ext->state) {
1034 rets = 0;
1035 DBG("successfully disconnected from fw client.\n");
1036 } else {
1037 rets = -ENODEV;
1038 if (HECI_FILE_DISCONNECTED != file_ext->state)
1039 DBG("wrong status client disconnect.\n");
1041 if (err)
1042 DBG("wait failed disconnect err=%08x\n", err);
1044 DBG("failed to disconnect from fw client.\n");
1047 spin_lock_bh(&dev->device_lock);
1048 heci_flush_list(&dev->ctrl_rd_list, file_ext);
1049 heci_flush_list(&dev->ctrl_wr_list, file_ext);
1050 spin_unlock_bh(&dev->device_lock);
1051 free:
1052 heci_free_cb_private(priv_cb);
1053 return rets;
1057 * heci_remove_client_from_file_list -
1058 * remove file private data from device file list
1060 * @dev: Device object for our driver
1061 * @host_client_id: host client id to be removed
1063 void heci_remove_client_from_file_list(struct iamt_heci_device *dev,
1064 __u8 host_client_id)
1066 struct heci_file_private *file_pos = NULL;
1067 struct heci_file_private *file_next = NULL;
1068 list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) {
1069 if (host_client_id == file_pos->host_client_id) {
1070 DBG("remove host client = %d, ME client = %d\n",
1071 file_pos->host_client_id,
1072 file_pos->me_client_id);
1073 list_del_init(&file_pos->link);
1074 break;