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>
53 #include "heci_data_structures.h"
54 #include "heci_interface.h"
58 const __u8 heci_start_wd_params
[] = { 0x02, 0x12, 0x13, 0x10 };
59 const __u8 heci_stop_wd_params
[] = { 0x02, 0x02, 0x14, 0x10 };
61 const __u8 heci_wd_state_independence_msg
[3][4] = {
62 {0x05, 0x02, 0x51, 0x10},
63 {0x05, 0x02, 0x52, 0x10},
64 {0x07, 0x02, 0x01, 0x10}
67 const struct guid heci_asf_guid
= {
68 0x75B30CD6, 0xA29E, 0x4AF7,
69 {0xA7, 0x12, 0xE6, 0x17, 0x43, 0x93, 0xC8, 0xA6}
71 const struct guid heci_wd_guid
= {
72 0x05B79A6F, 0x4628, 0x4D7F,
73 {0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB}
75 const struct guid heci_pthi_guid
= {
76 0x12f80028, 0xb4b7, 0x4b2d,
77 {0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c}
82 * heci init function prototypes
84 static void heci_check_asf_mode(struct iamt_heci_device
*dev
);
85 static int host_start_message(struct iamt_heci_device
*dev
);
86 static int host_enum_clients_message(struct iamt_heci_device
*dev
);
87 static int allocate_me_clients_storage(struct iamt_heci_device
*dev
);
88 static void host_init_wd(struct iamt_heci_device
*dev
);
89 static void host_init_iamthif(struct iamt_heci_device
*dev
);
90 static int heci_wait_event_int_timeout(struct iamt_heci_device
*dev
,
95 * heci_initialize_list - Sets up a queue list.
97 * @list: An instance of our list structure
98 * @dev: Device object for our driver
100 void heci_initialize_list(struct io_heci_list
*list
,
101 struct iamt_heci_device
*dev
)
103 /* initialize our queue list */
104 INIT_LIST_HEAD(&list
->heci_cb
.cb_list
);
106 list
->device_extension
= dev
;
110 * heci_flush_queues - flush our queues list belong to file_ext.
112 * @dev: Device object for our driver
113 * @file_ext: private data of the file object
115 void heci_flush_queues(struct iamt_heci_device
*dev
,
116 struct heci_file_private
*file_ext
)
120 if (!dev
|| !file_ext
)
123 /* flush our queue list belong to file_ext */
124 for (i
= 0; i
< HECI_IO_LISTS_NUMBER
; i
++) {
125 DBG("remove list entry belong to file_ext\n");
126 heci_flush_list(dev
->io_list_array
[i
], file_ext
);
132 * heci_flush_list - remove list entry belong to file_ext.
134 * @list: An instance of our list structure
135 * @file_ext: private data of the file object
137 void heci_flush_list(struct io_heci_list
*list
,
138 struct heci_file_private
*file_ext
)
140 struct heci_file_private
*file_ext_tmp
;
141 struct heci_cb_private
*priv_cb_pos
= NULL
;
142 struct heci_cb_private
*priv_cb_next
= NULL
;
144 if (!list
|| !file_ext
)
147 if (list
->status
!= 0)
150 if (list_empty(&list
->heci_cb
.cb_list
))
153 list_for_each_entry_safe(priv_cb_pos
, priv_cb_next
,
154 &list
->heci_cb
.cb_list
, cb_list
) {
156 file_ext_tmp
= (struct heci_file_private
*)
157 priv_cb_pos
->file_private
;
159 if (heci_fe_same_id(file_ext
, file_ext_tmp
))
160 list_del(&priv_cb_pos
->cb_list
);
167 * heci_reset_iamthif_params - initializes heci device iamthif
169 * @dev: The heci device structure
171 static void heci_reset_iamthif_params(struct iamt_heci_device
*dev
)
173 /* reset iamthif parameters. */
174 dev
->iamthif_current_cb
= NULL
;
175 dev
->iamthif_msg_buf_size
= 0;
176 dev
->iamthif_msg_buf_index
= 0;
177 dev
->iamthif_canceled
= 0;
178 dev
->iamthif_file_ext
.file
= NULL
;
179 dev
->iamthif_ioctl
= 0;
180 dev
->iamthif_state
= HECI_IAMTHIF_IDLE
;
181 dev
->iamthif_timer
= 0;
185 * init_heci_device - allocates and initializes the heci device structure
187 * @pdev: The pci device structure
189 * returns The heci_device_device pointer on success, NULL on failure.
191 struct iamt_heci_device
*init_heci_device(struct pci_dev
*pdev
)
194 struct iamt_heci_device
*dev
;
196 dev
= kzalloc(sizeof(struct iamt_heci_device
), GFP_KERNEL
);
200 /* setup our list array */
201 dev
->io_list_array
[0] = &dev
->read_list
;
202 dev
->io_list_array
[1] = &dev
->write_list
;
203 dev
->io_list_array
[2] = &dev
->write_waiting_list
;
204 dev
->io_list_array
[3] = &dev
->ctrl_wr_list
;
205 dev
->io_list_array
[4] = &dev
->ctrl_rd_list
;
206 dev
->io_list_array
[5] = &dev
->pthi_cmd_list
;
207 dev
->io_list_array
[6] = &dev
->pthi_read_complete_list
;
208 INIT_LIST_HEAD(&dev
->file_list
);
209 INIT_LIST_HEAD(&dev
->wd_file_ext
.link
);
210 INIT_LIST_HEAD(&dev
->iamthif_file_ext
.link
);
211 spin_lock_init(&dev
->device_lock
);
212 init_waitqueue_head(&dev
->wait_recvd_msg
);
213 init_waitqueue_head(&dev
->wait_stop_wd
);
214 dev
->heci_state
= HECI_INITIALIZING
;
215 dev
->iamthif_state
= HECI_IAMTHIF_IDLE
;
217 /* init work for schedule work */
218 INIT_WORK(&dev
->work
, NULL
);
219 for (i
= 0; i
< HECI_IO_LISTS_NUMBER
; i
++)
220 heci_initialize_list(dev
->io_list_array
[i
], dev
);
228 static int heci_wait_event_int_timeout(struct iamt_heci_device
*dev
,
231 return wait_event_interruptible_timeout(dev
->wait_recvd_msg
,
232 (dev
->recvd_msg
), timeout
);
236 * heci_hw_init - init host and fw to start work.
238 * @dev: Device object for our driver
240 * returns 0 on success, <0 on failure.
242 int heci_hw_init(struct iamt_heci_device
*dev
)
246 dev
->host_hw_state
= read_heci_register(dev
, H_CSR
);
247 dev
->me_hw_state
= read_heci_register(dev
, ME_CSR_HA
);
248 DBG("host_hw_state = 0x%08x, mestate = 0x%08x.\n",
249 dev
->host_hw_state
, dev
->me_hw_state
);
251 if ((dev
->host_hw_state
& H_IS
) == H_IS
) {
252 /* acknowledge interrupt and stop interupts */
253 heci_set_csr_register(dev
);
256 DBG("reset in start the heci device.\n");
260 DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
261 dev
->host_hw_state
, dev
->me_hw_state
);
263 /* wait for ME to turn on ME_RDY */
265 err
= heci_wait_event_int_timeout(dev
, HECI_INTEROP_TIMEOUT
);
267 if (!err
&& !dev
->recvd_msg
) {
268 dev
->heci_state
= HECI_DISABLED
;
269 DBG("wait_event_interruptible_timeout failed"
270 "on wait for ME to turn on ME_RDY.\n");
273 if (!(((dev
->host_hw_state
& H_RDY
) == H_RDY
)
274 && ((dev
->me_hw_state
& ME_RDY_HRA
) == ME_RDY_HRA
))) {
275 dev
->heci_state
= HECI_DISABLED
;
276 DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
280 if (!(dev
->host_hw_state
& H_RDY
) != H_RDY
)
281 DBG("host turn off H_RDY.\n");
283 if (!(dev
->me_hw_state
& ME_RDY_HRA
) != ME_RDY_HRA
)
284 DBG("ME turn off ME_RDY.\n");
287 "heci: link layer initialization failed.\n");
292 DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
293 dev
->host_hw_state
, dev
->me_hw_state
);
294 DBG("ME turn on ME_RDY and host turn on H_RDY.\n");
295 printk(KERN_INFO
"heci: link layer has been established.\n");
300 * heci_hw_reset - reset fw via heci csr register.
302 * @dev: Device object for our driver
303 * @interrupts: if interrupt should be enable after reset.
305 static void heci_hw_reset(struct iamt_heci_device
*dev
, int interrupts
)
307 dev
->host_hw_state
|= (H_RST
| H_IG
);
310 heci_csr_enable_interrupts(dev
);
312 heci_csr_disable_interrupts(dev
);
314 BUG_ON((dev
->host_hw_state
& H_RST
) != H_RST
);
315 BUG_ON((dev
->host_hw_state
& H_RDY
) != 0);
319 * heci_reset - reset host and fw.
321 * @dev: Device object for our driver
322 * @interrupts: if interrupt should be enable after reset.
324 void heci_reset(struct iamt_heci_device
*dev
, int interrupts
)
326 struct heci_file_private
*file_pos
= NULL
;
327 struct heci_file_private
*file_next
= NULL
;
328 struct heci_cb_private
*priv_cb_pos
= NULL
;
329 struct heci_cb_private
*priv_cb_next
= NULL
;
332 if (dev
->heci_state
== HECI_RECOVERING_FROM_RESET
) {
337 if (dev
->heci_state
!= HECI_INITIALIZING
&&
338 dev
->heci_state
!= HECI_DISABLED
&&
339 dev
->heci_state
!= HECI_POWER_DOWN
&&
340 dev
->heci_state
!= HECI_POWER_UP
)
343 if (dev
->reinit_tsk
!= NULL
) {
344 kthread_stop(dev
->reinit_tsk
);
345 dev
->reinit_tsk
= NULL
;
348 dev
->host_hw_state
= read_heci_register(dev
, H_CSR
);
350 DBG("before reset host_hw_state = 0x%08x.\n",
353 heci_hw_reset(dev
, interrupts
);
355 dev
->host_hw_state
&= ~H_RST
;
356 dev
->host_hw_state
|= H_IG
;
358 write_heci_register(dev
, H_CSR
, dev
->host_hw_state
);
360 DBG("currently saved host_hw_state = 0x%08x.\n",
365 if (dev
->heci_state
!= HECI_INITIALIZING
) {
366 if ((dev
->heci_state
!= HECI_DISABLED
) &&
367 (dev
->heci_state
!= HECI_POWER_DOWN
))
368 dev
->heci_state
= HECI_RESETING
;
370 list_for_each_entry_safe(file_pos
,
371 file_next
, &dev
->file_list
, link
) {
372 file_pos
->state
= HECI_FILE_DISCONNECTED
;
373 file_pos
->flow_ctrl_creds
= 0;
374 file_pos
->read_cb
= NULL
;
375 file_pos
->timer_count
= 0;
377 /* remove entry if already in list */
378 DBG("list del iamthif and wd file list.\n");
379 heci_remove_client_from_file_list(dev
,
380 dev
->wd_file_ext
.host_client_id
);
382 heci_remove_client_from_file_list(dev
,
383 dev
->iamthif_file_ext
.host_client_id
);
385 heci_reset_iamthif_params(dev
);
386 dev
->wd_due_counter
= 0;
387 dev
->extra_write_index
= 0;
390 dev
->num_heci_me_clients
= 0;
395 /* update the state of the registers after reset */
396 dev
->host_hw_state
= read_heci_register(dev
, H_CSR
);
397 dev
->me_hw_state
= read_heci_register(dev
, ME_CSR_HA
);
399 DBG("after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
400 dev
->host_hw_state
, dev
->me_hw_state
);
403 printk(KERN_WARNING
"heci: unexpected reset.\n");
405 /* Wake up all readings so they can be interrupted */
406 list_for_each_entry_safe(file_pos
, file_next
, &dev
->file_list
, link
) {
407 if (&file_pos
->rx_wait
&&
408 waitqueue_active(&file_pos
->rx_wait
)) {
409 printk(KERN_INFO
"heci: Waking up client!\n");
410 wake_up_interruptible(&file_pos
->rx_wait
);
413 /* remove all waiting requests */
414 if (dev
->write_list
.status
== 0 &&
415 !list_empty(&dev
->write_list
.heci_cb
.cb_list
)) {
416 list_for_each_entry_safe(priv_cb_pos
, priv_cb_next
,
417 &dev
->write_list
.heci_cb
.cb_list
, cb_list
) {
419 list_del(&priv_cb_pos
->cb_list
);
420 heci_free_cb_private(priv_cb_pos
);
427 * heci_initialize_clients - heci communication initialization.
429 * @dev: Device object for our driver
431 int heci_initialize_clients(struct iamt_heci_device
*dev
)
435 msleep(100); /* FW needs time to be ready to talk with us */
436 DBG("link is established start sending messages.\n");
437 /* link is established start sending messages. */
438 status
= host_start_message(dev
);
440 spin_lock_bh(&dev
->device_lock
);
441 dev
->heci_state
= HECI_DISABLED
;
442 spin_unlock_bh(&dev
->device_lock
);
443 DBG("start sending messages failed.\n");
447 /* enumerate clients */
448 status
= host_enum_clients_message(dev
);
450 spin_lock_bh(&dev
->device_lock
);
451 dev
->heci_state
= HECI_DISABLED
;
452 spin_unlock_bh(&dev
->device_lock
);
453 DBG("enum clients failed.\n");
456 /* allocate storage for ME clients representation */
457 status
= allocate_me_clients_storage(dev
);
459 spin_lock_bh(&dev
->device_lock
);
460 dev
->num_heci_me_clients
= 0;
461 dev
->heci_state
= HECI_DISABLED
;
462 spin_unlock_bh(&dev
->device_lock
);
463 DBG("allocate clients failed.\n");
467 heci_check_asf_mode(dev
);
468 /*heci initialization wd */
470 /*heci initialization iamthif client */
471 host_init_iamthif(dev
);
473 spin_lock_bh(&dev
->device_lock
);
474 if (dev
->need_reset
) {
476 dev
->heci_state
= HECI_DISABLED
;
477 spin_unlock_bh(&dev
->device_lock
);
481 memset(dev
->heci_host_clients
, 0, sizeof(dev
->heci_host_clients
));
482 dev
->open_handle_count
= 0;
483 dev
->heci_host_clients
[0] |= 7;
484 dev
->current_host_client_id
= 3;
485 dev
->heci_state
= HECI_ENABLED
;
486 spin_unlock_bh(&dev
->device_lock
);
487 DBG("initialization heci clients successful.\n");
492 * heci_task_initialize_clients - heci reinitialization task
494 * @data: Device object for our driver
496 int heci_task_initialize_clients(void *data
)
499 struct iamt_heci_device
*dev
= (struct iamt_heci_device
*) data
;
501 spin_lock_bh(&dev
->device_lock
);
502 if (dev
->reinit_tsk
!= NULL
) {
503 spin_unlock_bh(&dev
->device_lock
);
504 DBG("reinit task already started.\n");
507 dev
->reinit_tsk
= current
;
508 current
->flags
|= PF_NOFREEZE
;
509 spin_unlock_bh(&dev
->device_lock
);
511 ret
= heci_initialize_clients(dev
);
513 spin_lock_bh(&dev
->device_lock
);
514 dev
->reinit_tsk
= NULL
;
515 spin_unlock_bh(&dev
->device_lock
);
521 * host_start_message - heci host send start message.
523 * @dev: Device object for our driver
525 * returns 0 on success, <0 on failure.
527 static int host_start_message(struct iamt_heci_device
*dev
)
529 long timeout
= 60; /* 60 second */
531 struct heci_msg_hdr
*heci_hdr
;
532 struct hbm_host_version_request
*host_start_req
;
533 struct hbm_host_stop_request
*host_stop_req
;
536 /* host start message */
537 heci_hdr
= (struct heci_msg_hdr
*) &dev
->wr_msg_buf
[0];
538 heci_hdr
->host_addr
= 0;
539 heci_hdr
->me_addr
= 0;
540 heci_hdr
->length
= sizeof(struct hbm_host_version_request
);
541 heci_hdr
->msg_complete
= 1;
542 heci_hdr
->reserved
= 0;
545 (struct hbm_host_version_request
*) &dev
->wr_msg_buf
[1];
546 memset(host_start_req
, 0, sizeof(struct hbm_host_version_request
));
547 host_start_req
->cmd
.cmd
= HOST_START_REQ_CMD
;
548 host_start_req
->host_version
.major_version
= HBM_MAJOR_VERSION
;
549 host_start_req
->host_version
.minor_version
= HBM_MINOR_VERSION
;
551 if (!heci_write_message(dev
, heci_hdr
,
552 (unsigned char *) (host_start_req
),
554 DBG("send version to fw fail.\n");
557 DBG("call wait_event_interruptible_timeout for response message.\n");
558 /* wait for response */
559 err
= heci_wait_event_int_timeout(dev
, timeout
* HZ
);
560 if (!err
&& !dev
->recvd_msg
) {
561 DBG("wait_timeout failed on host start response message.\n");
565 DBG("wait_timeout successful on host start response message.\n");
566 if ((dev
->version
.major_version
!= HBM_MAJOR_VERSION
) ||
567 (dev
->version
.minor_version
!= HBM_MINOR_VERSION
)) {
568 /* send stop message */
569 heci_hdr
->host_addr
= 0;
570 heci_hdr
->me_addr
= 0;
571 heci_hdr
->length
= sizeof(struct hbm_host_stop_request
);
572 heci_hdr
->msg_complete
= 1;
573 heci_hdr
->reserved
= 0;
576 (struct hbm_host_stop_request
*) &dev
->wr_msg_buf
[1];
578 memset(host_stop_req
, 0, sizeof(struct hbm_host_stop_request
));
579 host_stop_req
->cmd
.cmd
= HOST_STOP_REQ_CMD
;
580 host_stop_req
->reason
= DRIVER_STOP_REQUEST
;
581 heci_write_message(dev
, heci_hdr
,
582 (unsigned char *) (host_stop_req
),
584 DBG("version mismatch.\n");
592 * host_enum_clients_message - host send enumeration client request message.
594 * @dev: Device object for our driver
596 * returns 0 on success, <0 on failure.
598 static int host_enum_clients_message(struct iamt_heci_device
*dev
)
600 long timeout
= 5; /*5 second */
601 struct heci_msg_hdr
*heci_hdr
;
602 struct hbm_host_enum_request
*host_enum_req
;
606 heci_hdr
= (struct heci_msg_hdr
*) &dev
->wr_msg_buf
[0];
607 /* enumerate clients */
608 heci_hdr
->host_addr
= 0;
609 heci_hdr
->me_addr
= 0;
610 heci_hdr
->length
= sizeof(struct hbm_host_enum_request
);
611 heci_hdr
->msg_complete
= 1;
612 heci_hdr
->reserved
= 0;
614 host_enum_req
= (struct hbm_host_enum_request
*) &dev
->wr_msg_buf
[1];
615 memset(host_enum_req
, 0, sizeof(struct hbm_host_enum_request
));
616 host_enum_req
->cmd
.cmd
= HOST_ENUM_REQ_CMD
;
617 if (!heci_write_message(dev
, heci_hdr
,
618 (unsigned char *) (host_enum_req
),
620 DBG("send enumeration request failed.\n");
623 /* wait for response */
625 err
= heci_wait_event_int_timeout(dev
, timeout
* HZ
);
626 if (!err
&& !dev
->recvd_msg
) {
627 DBG("wait_event_interruptible_timeout failed "
628 "on enumeration clients response message.\n");
633 spin_lock_bh(&dev
->device_lock
);
634 /* count how many ME clients we have */
635 for (i
= 0; i
< sizeof(dev
->heci_me_clients
); i
++) {
636 for (j
= 0; j
< 8; j
++) {
637 if ((dev
->heci_me_clients
[i
] & (1 << j
)) != 0)
638 dev
->num_heci_me_clients
++;
642 spin_unlock_bh(&dev
->device_lock
);
648 * host_client_properties - reads properties for client
650 * @dev: Device object for our driver
651 * @idx: client index in me client array
652 * @client_id: id of the client
654 * returns 0 on success, <0 on failure.
656 static int host_client_properties(struct iamt_heci_device
*dev
,
657 struct heci_me_client
*client
)
659 struct heci_msg_hdr
*heci_hdr
;
660 struct hbm_props_request
*host_cli_req
;
663 heci_hdr
= (struct heci_msg_hdr
*) &dev
->wr_msg_buf
[0];
664 heci_hdr
->host_addr
= 0;
665 heci_hdr
->me_addr
= 0;
666 heci_hdr
->length
= sizeof(struct hbm_props_request
);
667 heci_hdr
->msg_complete
= 1;
668 heci_hdr
->reserved
= 0;
670 host_cli_req
= (struct hbm_props_request
*) &dev
->wr_msg_buf
[1];
671 memset(host_cli_req
, 0, sizeof(struct hbm_props_request
));
672 host_cli_req
->cmd
.cmd
= HOST_CLIENT_PROPERTEIS_REQ_CMD
;
673 host_cli_req
->address
= client
->client_id
;
674 if (!heci_write_message(dev
, heci_hdr
,
675 (unsigned char *) (host_cli_req
),
677 DBG("send props request failed.\n");
680 /* wait for response */
682 err
= heci_wait_event_int_timeout(dev
, 10 * HZ
);
683 if (!err
&& !dev
->recvd_msg
) {
684 DBG("wait failed on props resp msg.\n");
692 * allocate_me_clients_storage - allocate storage for me clients
694 * @dev: Device object for our driver
696 * returns 0 on success, <0 on failure.
698 static int allocate_me_clients_storage(struct iamt_heci_device
*dev
)
700 struct heci_me_client
*clients
;
701 struct heci_me_client
*client
;
705 if (dev
->num_heci_me_clients
<= 0)
708 spin_lock_bh(&dev
->device_lock
);
709 kfree(dev
->me_clients
);
710 dev
->me_clients
= NULL
;
711 spin_unlock_bh(&dev
->device_lock
);
713 /* allocate storage for ME clients representation */
714 clients
= kcalloc(dev
->num_heci_me_clients
,
715 sizeof(struct heci_me_client
), GFP_KERNEL
);
717 DBG("memory allocation for ME clients failed.\n");
721 spin_lock_bh(&dev
->device_lock
);
722 dev
->me_clients
= clients
;
723 spin_unlock_bh(&dev
->device_lock
);
726 for (i
= 0; i
< sizeof(dev
->heci_me_clients
); i
++) {
727 for (j
= 0; j
< 8; j
++) {
728 if ((dev
->heci_me_clients
[i
] & (1 << j
)) != 0) {
729 client
= &dev
->me_clients
[num
];
730 client
->client_id
= (i
* 8) + j
;
731 client
->flow_ctrl_creds
= 0;
732 err
= host_client_properties(dev
, client
);
734 spin_lock_bh(&dev
->device_lock
);
735 kfree(dev
->me_clients
);
736 dev
->me_clients
= NULL
;
737 spin_unlock_bh(&dev
->device_lock
);
749 * heci_init_file_private - initializes private file structure.
751 * @priv: private file structure to be initialized
752 * @file: the file structure
754 static void heci_init_file_private(struct heci_file_private
*priv
,
757 memset(priv
, 0, sizeof(struct heci_file_private
));
758 spin_lock_init(&priv
->file_lock
);
759 spin_lock_init(&priv
->read_io_lock
);
760 spin_lock_init(&priv
->write_io_lock
);
761 init_waitqueue_head(&priv
->wait
);
762 init_waitqueue_head(&priv
->rx_wait
);
763 DBG("priv->rx_wait =%p\n", &priv
->rx_wait
);
764 init_waitqueue_head(&priv
->tx_wait
);
765 INIT_LIST_HEAD(&priv
->link
);
766 priv
->reading_state
= HECI_IDLE
;
767 priv
->writing_state
= HECI_IDLE
;
771 * heci_find_me_client - search for ME client guid
772 * sets client_id in heci_file_private if found
773 * @dev: Device object for our driver
774 * @priv: private file structure to set client_id in
775 * @cguid: searched guid of ME client
776 * @client_id: id of host client to be set in file private structure
778 * returns ME client index
780 static __u8
heci_find_me_client(struct iamt_heci_device
*dev
,
781 struct heci_file_private
*priv
,
782 const struct guid
*cguid
, __u8 client_id
)
786 if ((dev
== NULL
) || (priv
== NULL
) || (cguid
== NULL
))
789 for (i
= 0; i
< dev
->num_heci_me_clients
; i
++) {
791 &dev
->me_clients
[i
].props
.protocol_name
,
792 sizeof(struct guid
)) == 0) {
793 priv
->me_client_id
= dev
->me_clients
[i
].client_id
;
794 priv
->state
= HECI_FILE_CONNECTING
;
795 priv
->host_client_id
= client_id
;
797 list_add_tail(&priv
->link
, &dev
->file_list
);
805 * heci_check_asf_mode - check for ASF client
807 * @dev: Device object for our driver
809 static void heci_check_asf_mode(struct iamt_heci_device
*dev
)
813 spin_lock_bh(&dev
->device_lock
);
815 /* find ME ASF client - otherwise assume AMT mode */
816 DBG("find ME ASF client - otherwise assume AMT mode.\n");
817 for (i
= 0; i
< dev
->num_heci_me_clients
; i
++) {
818 if (memcmp(&heci_asf_guid
,
819 &dev
->me_clients
[i
].props
.protocol_name
,
820 sizeof(struct guid
)) == 0) {
822 spin_unlock_bh(&dev
->device_lock
);
823 DBG("found ME ASF client.\n");
827 spin_unlock_bh(&dev
->device_lock
);
828 DBG("assume AMT mode.\n");
832 * heci_connect_me_client - connect ME client
833 * @dev: Device object for our driver
834 * @priv: private file structure
835 * @timeout: connect timeout in seconds
837 * returns 1 - if connected, 0 - if not
839 static __u8
heci_connect_me_client(struct iamt_heci_device
*dev
,
840 struct heci_file_private
*priv
,
845 if ((dev
== NULL
) || (priv
== NULL
))
848 if (!heci_connect(dev
, priv
)) {
849 DBG("failed to call heci_connect for client_id=%d.\n",
850 priv
->host_client_id
);
851 spin_lock_bh(&dev
->device_lock
);
852 heci_remove_client_from_file_list(dev
, priv
->host_client_id
);
853 priv
->state
= HECI_FILE_DISCONNECTED
;
854 spin_unlock_bh(&dev
->device_lock
);
858 err
= wait_event_timeout(dev
->wait_recvd_msg
,
859 (HECI_FILE_CONNECTED
== priv
->state
||
860 HECI_FILE_DISCONNECTED
== priv
->state
),
862 if (HECI_FILE_CONNECTED
!= priv
->state
) {
863 spin_lock_bh(&dev
->device_lock
);
864 heci_remove_client_from_file_list(dev
, priv
->host_client_id
);
865 DBG("failed to connect client_id=%d state=%d.\n",
866 priv
->host_client_id
, priv
->state
);
868 DBG("failed connect err=%08x\n", err
);
869 priv
->state
= HECI_FILE_DISCONNECTED
;
870 spin_unlock_bh(&dev
->device_lock
);
873 DBG("successfully connected client_id=%d.\n",
874 priv
->host_client_id
);
879 * host_init_wd - heci initialization wd.
881 * @dev: Device object for our driver
883 static void host_init_wd(struct iamt_heci_device
*dev
)
885 spin_lock_bh(&dev
->device_lock
);
887 heci_init_file_private(&dev
->wd_file_ext
, NULL
);
889 /* look for WD client and connect to it */
890 dev
->wd_file_ext
.state
= HECI_FILE_DISCONNECTED
;
894 memcpy(dev
->wd_data
, heci_stop_wd_params
, HECI_WD_PARAMS_SIZE
);
897 dev
->wd_timeout
= AMT_WD_VALUE
;
898 DBG("dev->wd_timeout=%d.\n", dev
->wd_timeout
);
899 memcpy(dev
->wd_data
, heci_start_wd_params
, HECI_WD_PARAMS_SIZE
);
900 memcpy(dev
->wd_data
+ HECI_WD_PARAMS_SIZE
,
901 &dev
->wd_timeout
, sizeof(__u16
));
904 /* find ME WD client */
905 heci_find_me_client(dev
, &dev
->wd_file_ext
,
906 &heci_wd_guid
, HECI_WD_HOST_CLIENT_ID
);
907 spin_unlock_bh(&dev
->device_lock
);
909 DBG("check wd_file_ext\n");
910 if (HECI_FILE_CONNECTING
== dev
->wd_file_ext
.state
) {
911 if (heci_connect_me_client(dev
, &dev
->wd_file_ext
, 15) == 1) {
912 DBG("dev->wd_timeout=%d.\n", dev
->wd_timeout
);
913 if (dev
->wd_timeout
!= 0)
914 dev
->wd_due_counter
= 1;
916 dev
->wd_due_counter
= 0;
917 DBG("successfully connected to WD client.\n");
920 DBG("failed to find WD client.\n");
923 spin_lock_bh(&dev
->device_lock
);
924 dev
->wd_timer
.function
= &heci_wd_timer
;
925 dev
->wd_timer
.data
= (unsigned long) dev
;
926 spin_unlock_bh(&dev
->device_lock
);
931 * host_init_iamthif - heci initialization iamthif client.
933 * @dev: Device object for our driver
936 static void host_init_iamthif(struct iamt_heci_device
*dev
)
940 spin_lock_bh(&dev
->device_lock
);
942 heci_init_file_private(&dev
->iamthif_file_ext
, NULL
);
943 dev
->iamthif_file_ext
.state
= HECI_FILE_DISCONNECTED
;
945 /* find ME PTHI client */
946 i
= heci_find_me_client(dev
, &dev
->iamthif_file_ext
,
947 &heci_pthi_guid
, HECI_IAMTHIF_HOST_CLIENT_ID
);
948 if (dev
->iamthif_file_ext
.state
!= HECI_FILE_CONNECTING
) {
949 DBG("failed to find iamthif client.\n");
950 spin_unlock_bh(&dev
->device_lock
);
954 BUG_ON(dev
->me_clients
[i
].props
.max_msg_length
!= IAMTHIF_MTU
);
956 spin_unlock_bh(&dev
->device_lock
);
957 if (heci_connect_me_client(dev
, &dev
->iamthif_file_ext
, 15) == 1) {
958 DBG("connected to iamthif client.\n");
959 dev
->iamthif_state
= HECI_IAMTHIF_IDLE
;
964 * heci_alloc_file_private - allocates a private file structure and set it up.
965 * @file: the file structure
967 * returns The allocated file or NULL on failure
969 struct heci_file_private
*heci_alloc_file_private(struct file
*file
)
971 struct heci_file_private
*priv
;
973 priv
= kmalloc(sizeof(struct heci_file_private
), GFP_KERNEL
);
977 heci_init_file_private(priv
, file
);
985 * heci_disconnect_host_client - send disconnect message to fw from host client.
987 * @dev: Device object for our driver
988 * @file_ext: private data of the file object
990 * returns 0 on success, <0 on failure.
992 int heci_disconnect_host_client(struct iamt_heci_device
*dev
,
993 struct heci_file_private
*file_ext
)
996 long timeout
= 15; /* 15 seconds */
997 struct heci_cb_private
*priv_cb
;
999 if ((!dev
) || (!file_ext
))
1002 if (file_ext
->state
!= HECI_FILE_DISCONNECTING
)
1005 priv_cb
= kzalloc(sizeof(struct heci_cb_private
), GFP_KERNEL
);
1009 INIT_LIST_HEAD(&priv_cb
->cb_list
);
1010 priv_cb
->file_private
= file_ext
;
1011 priv_cb
->major_file_operations
= HECI_CLOSE
;
1012 spin_lock_bh(&dev
->device_lock
);
1013 if (dev
->host_buffer_is_empty
) {
1014 dev
->host_buffer_is_empty
= 0;
1015 if (heci_disconnect(dev
, file_ext
)) {
1016 list_add_tail(&priv_cb
->cb_list
,
1017 &dev
->ctrl_rd_list
.heci_cb
.cb_list
);
1019 spin_unlock_bh(&dev
->device_lock
);
1021 DBG("failed to call heci_disconnect.\n");
1025 DBG("add disconnect cb to control write list\n");
1026 list_add_tail(&priv_cb
->cb_list
,
1027 &dev
->ctrl_wr_list
.heci_cb
.cb_list
);
1029 spin_unlock_bh(&dev
->device_lock
);
1031 err
= wait_event_timeout(dev
->wait_recvd_msg
,
1032 (HECI_FILE_DISCONNECTED
== file_ext
->state
),
1034 if (HECI_FILE_DISCONNECTED
== file_ext
->state
) {
1036 DBG("successfully disconnected from fw client.\n");
1039 if (HECI_FILE_DISCONNECTED
!= file_ext
->state
)
1040 DBG("wrong status client disconnect.\n");
1043 DBG("wait failed disconnect err=%08x\n", err
);
1045 DBG("failed to disconnect from fw client.\n");
1048 spin_lock_bh(&dev
->device_lock
);
1049 heci_flush_list(&dev
->ctrl_rd_list
, file_ext
);
1050 heci_flush_list(&dev
->ctrl_wr_list
, file_ext
);
1051 spin_unlock_bh(&dev
->device_lock
);
1053 heci_free_cb_private(priv_cb
);
1058 * heci_remove_client_from_file_list -
1059 * remove file private data from device file list
1061 * @dev: Device object for our driver
1062 * @host_client_id: host client id to be removed
1064 void heci_remove_client_from_file_list(struct iamt_heci_device
*dev
,
1065 __u8 host_client_id
)
1067 struct heci_file_private
*file_pos
= NULL
;
1068 struct heci_file_private
*file_next
= NULL
;
1069 list_for_each_entry_safe(file_pos
, file_next
, &dev
->file_list
, link
) {
1070 if (host_client_id
== file_pos
->host_client_id
) {
1071 DBG("remove host client = %d, ME client = %d\n",
1072 file_pos
->host_client_id
,
1073 file_pos
->me_client_id
);
1074 list_del_init(&file_pos
->link
);