2 * Part of Intel(R) Manageability Engine Interface Linux driver
4 * Copyright (c) 2003 - 2008 Intel Corp.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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"
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
,
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
);
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
)
119 if (!dev
|| !file_ext
)
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
)
146 if (list
->status
!= 0)
149 if (list_empty(&list
->heci_cb
.cb_list
))
152 list_for_each_entry_safe(priv_cb_pos
, priv_cb_next
,
153 &list
->heci_cb
.cb_list
, cb_list
) {
155 file_ext_tmp
= (struct heci_file_private
*)
156 priv_cb_pos
->file_private
;
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
)
193 struct iamt_heci_device
*dev
;
195 dev
= kzalloc(sizeof(struct iamt_heci_device
), GFP_KERNEL
);
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
);
227 static int heci_wait_event_int_timeout(struct iamt_heci_device
*dev
,
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
)
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_csr_clear_his(dev
);
255 DBG("reset in start the heci device.\n");
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 */
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");
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",
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");
286 "heci: link layer initialization failed.\n");
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");
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
);
309 heci_csr_enable_interrupts(dev
);
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
;
331 if (dev
->heci_state
== HECI_RECOVERING_FROM_RESET
) {
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
)
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",
352 heci_hw_reset(dev
, interrupts
);
354 dev
->host_hw_state
&= ~H_RST
;
355 dev
->host_hw_state
|= H_IG
;
357 heci_set_csr_register(dev
);
359 DBG("currently saved host_hw_state = 0x%08x.\n",
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;
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
);
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
) {
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
)
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
);
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");
446 /* enumerate clients */
447 status
= host_enum_clients_message(dev
);
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");
455 /* allocate storage for ME clients representation */
456 status
= allocate_me_clients_storage(dev
);
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");
466 heci_check_asf_mode(dev
);
467 /*heci initialization wd */
469 /*heci initialization iamthif client */
470 host_init_iamthif(dev
);
472 spin_lock_bh(&dev
->device_lock
);
473 if (dev
->need_reset
) {
475 dev
->heci_state
= HECI_DISABLED
;
476 spin_unlock_bh(&dev
->device_lock
);
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");
491 * heci_task_initialize_clients - heci reinitialization task
493 * @data: Device object for our driver
495 int heci_task_initialize_clients(void *data
)
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");
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
);
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
;
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;
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
;
550 if (!heci_write_message(dev
, heci_hdr
,
551 (unsigned char *) (host_start_req
),
553 DBG("send version to fw fail.\n");
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");
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;
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
),
583 DBG("version mismatch.\n");
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
;
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
),
619 DBG("send enumeration request failed.\n");
622 /* wait for response */
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");
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
);
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
;
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
),
676 DBG("send props request failed.\n");
679 /* wait for response */
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");
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
;
704 if (dev
->num_heci_me_clients
<= 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
);
716 DBG("memory allocation for ME clients failed.\n");
720 spin_lock_bh(&dev
->device_lock
);
721 dev
->me_clients
= clients
;
722 spin_unlock_bh(&dev
->device_lock
);
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
);
733 spin_lock_bh(&dev
->device_lock
);
734 kfree(dev
->me_clients
);
735 dev
->me_clients
= NULL
;
736 spin_unlock_bh(&dev
->device_lock
);
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
,
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
)
785 if ((dev
== NULL
) || (priv
== NULL
) || (cguid
== NULL
))
788 for (i
= 0; i
< dev
->num_heci_me_clients
; i
++) {
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
);
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
)
812 spin_lock_bh(&dev
->device_lock
);
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) {
821 spin_unlock_bh(&dev
->device_lock
);
822 DBG("found ME ASF client.\n");
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
,
844 if ((dev
== NULL
) || (priv
== NULL
))
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
);
857 err
= wait_event_timeout(dev
->wait_recvd_msg
,
858 (HECI_FILE_CONNECTED
== priv
->state
||
859 HECI_FILE_DISCONNECTED
== priv
->state
),
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
);
867 DBG("failed connect err=%08x\n", err
);
868 priv
->state
= HECI_FILE_DISCONNECTED
;
869 spin_unlock_bh(&dev
->device_lock
);
872 DBG("successfully connected client_id=%d.\n",
873 priv
->host_client_id
);
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
;
893 memcpy(dev
->wd_data
, heci_stop_wd_params
, HECI_WD_PARAMS_SIZE
);
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;
915 dev
->wd_due_counter
= 0;
916 DBG("successfully connected to WD client.\n");
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
)
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
);
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
);
976 heci_init_file_private(priv
, file
);
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
)
995 long timeout
= 15; /* 15 seconds */
996 struct heci_cb_private
*priv_cb
;
998 if ((!dev
) || (!file_ext
))
1001 spin_lock_bh(&dev
->device_lock
);
1002 if (file_ext
->state
!= HECI_FILE_DISCONNECTING
) {
1003 spin_unlock_bh(&dev
->device_lock
);
1006 spin_unlock_bh(&dev
->device_lock
);
1008 priv_cb
= kzalloc(sizeof(struct heci_cb_private
), GFP_KERNEL
);
1012 INIT_LIST_HEAD(&priv_cb
->cb_list
);
1013 priv_cb
->file_private
= file_ext
;
1014 priv_cb
->major_file_operations
= HECI_CLOSE
;
1015 spin_lock_bh(&dev
->device_lock
);
1016 if (dev
->host_buffer_is_empty
) {
1017 dev
->host_buffer_is_empty
= 0;
1018 if (heci_disconnect(dev
, file_ext
)) {
1019 mdelay(10); /* Wait for hardware disconnection ready */
1020 list_add_tail(&priv_cb
->cb_list
,
1021 &dev
->ctrl_rd_list
.heci_cb
.cb_list
);
1023 spin_unlock_bh(&dev
->device_lock
);
1025 DBG("failed to call heci_disconnect.\n");
1029 DBG("add disconnect cb to control write list\n");
1030 list_add_tail(&priv_cb
->cb_list
,
1031 &dev
->ctrl_wr_list
.heci_cb
.cb_list
);
1033 spin_unlock_bh(&dev
->device_lock
);
1035 err
= wait_event_timeout(dev
->wait_recvd_msg
,
1036 (HECI_FILE_DISCONNECTED
== file_ext
->state
),
1039 spin_lock_bh(&dev
->device_lock
);
1040 if (HECI_FILE_DISCONNECTED
== file_ext
->state
) {
1042 DBG("successfully disconnected from fw client.\n");
1045 if (HECI_FILE_DISCONNECTED
!= file_ext
->state
)
1046 DBG("wrong status client disconnect.\n");
1049 DBG("wait failed disconnect err=%08x\n", err
);
1051 DBG("failed to disconnect from fw client.\n");
1054 heci_flush_list(&dev
->ctrl_rd_list
, file_ext
);
1055 heci_flush_list(&dev
->ctrl_wr_list
, file_ext
);
1056 spin_unlock_bh(&dev
->device_lock
);
1058 heci_free_cb_private(priv_cb
);
1063 * heci_remove_client_from_file_list -
1064 * remove file private data from device file list
1066 * @dev: Device object for our driver
1067 * @host_client_id: host client id to be removed
1069 void heci_remove_client_from_file_list(struct iamt_heci_device
*dev
,
1070 __u8 host_client_id
)
1072 struct heci_file_private
*file_pos
= NULL
;
1073 struct heci_file_private
*file_next
= NULL
;
1074 list_for_each_entry_safe(file_pos
, file_next
, &dev
->file_list
, link
) {
1075 if (host_client_id
== file_pos
->host_client_id
) {
1076 DBG("remove host client = %d, ME client = %d\n",
1077 file_pos
->host_client_id
,
1078 file_pos
->me_client_id
);
1079 list_del_init(&file_pos
->link
);