Staging: add heci driver
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / heci / interrupt.c
blob54fcf90807d670bf3e8cf3790884099529d82964
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/kthread.h>
42 #include "kcompat.h"
44 #include "heci.h"
45 #include "heci_interface.h"
48 * interrupt function prototypes
50 static void heci_bh_handler(struct work_struct *work);
51 static int heci_bh_read_handler(struct io_heci_list *complete_list,
52 struct iamt_heci_device *dev,
53 __s32 *slots);
54 static int heci_bh_write_handler(struct io_heci_list *complete_list,
55 struct iamt_heci_device *dev,
56 __s32 *slots);
57 static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
58 struct heci_msg_hdr *heci_hdr);
59 static int heci_bh_read_pthi_message(struct io_heci_list *complete_list,
60 struct iamt_heci_device *dev,
61 struct heci_msg_hdr *heci_hdr);
62 static int heci_bh_read_client_message(struct io_heci_list *complete_list,
63 struct iamt_heci_device *dev,
64 struct heci_msg_hdr *heci_hdr);
65 static void heci_client_connect_response(struct iamt_heci_device *dev,
66 struct hbm_client_connect_response *connect_res);
67 static void heci_client_disconnect_response(struct iamt_heci_device *dev,
68 struct hbm_client_connect_response *disconnect_res);
69 static void heci_client_flow_control_response(struct iamt_heci_device *dev,
70 struct hbm_flow_control *flow_control);
71 static void heci_client_disconnect_request(struct iamt_heci_device *dev,
72 struct hbm_client_disconnect_request *disconnect_req);
75 /**
76 * heci_isr_interrupt - The ISR of the HECI device
78 * @irq: The irq number
79 * @dev_id: pointer to the device structure
81 * returns irqreturn_t
83 irqreturn_t heci_isr_interrupt(int irq, void *dev_id)
85 int err;
86 struct iamt_heci_device *dev = (struct iamt_heci_device *) dev_id;
88 dev->host_hw_state = read_heci_register(dev, H_CSR);
90 if ((dev->host_hw_state & H_IS) != H_IS)
91 return IRQ_NONE;
93 /* disable interrupts */
94 heci_csr_disable_interrupts(dev);
97 * Our device interrupted, schedule work the heci_bh_handler
98 * to handle the interrupt processing. This needs to be a
99 * workqueue item since the handler can sleep.
101 PREPARE_WORK(&dev->work, heci_bh_handler);
102 DBG("schedule work the heci_bh_handler.\n");
103 err = schedule_work(&dev->work);
104 if (!err) {
105 printk(KERN_ERR "heci: schedule the heci_bh_handler"
106 " failed error=%x\n", err);
108 return IRQ_HANDLED;
112 * _heci_cmpl - process completed operation.
114 * @file_ext: private data of the file object.
115 * @priv_cb_pos: callback block.
117 static void _heci_cmpl(struct heci_file_private *file_ext,
118 struct heci_cb_private *priv_cb_pos)
120 if (priv_cb_pos->major_file_operations == HECI_WRITE) {
121 heci_free_cb_private(priv_cb_pos);
122 DBG("completing write call back.\n");
123 file_ext->writing_state = HECI_WRITE_COMPLETE;
124 if ((&file_ext->tx_wait) &&
125 waitqueue_active(&file_ext->tx_wait))
126 wake_up_interruptible(&file_ext->tx_wait);
128 } else if (priv_cb_pos->major_file_operations == HECI_READ
129 && HECI_READING == file_ext->reading_state) {
130 DBG("completing read call back information= %lu\n",
131 priv_cb_pos->information);
132 file_ext->reading_state = HECI_READ_COMPLETE;
133 if ((&file_ext->rx_wait) &&
134 waitqueue_active(&file_ext->rx_wait))
135 wake_up_interruptible(&file_ext->rx_wait);
141 * _heci_cmpl_iamthif - process completed iamthif operation.
143 * @dev: Device object for our driver.
144 * @priv_cb_pos: callback block.
146 static void _heci_cmpl_iamthif(struct iamt_heci_device *dev,
147 struct heci_cb_private *priv_cb_pos)
149 if (dev->iamthif_canceled != 1) {
150 dev->iamthif_state = HECI_IAMTHIF_READ_COMPLETE;
151 dev->iamthif_stall_timer = 0;
152 memcpy(priv_cb_pos->response_buffer.data,
153 dev->iamthif_msg_buf,
154 dev->iamthif_msg_buf_index);
155 list_add_tail(&priv_cb_pos->cb_list,
156 &dev->pthi_read_complete_list.heci_cb.cb_list);
157 DBG("pthi read completed.\n");
158 } else {
159 run_next_iamthif_cmd(dev);
161 if (&dev->iamthif_file_ext.wait) {
162 DBG("completing pthi call back.\n");
163 wake_up_interruptible(&dev->iamthif_file_ext.wait);
167 * heci_bh_handler - function called after ISR to handle the interrupt
168 * processing.
170 * @work: pointer to the work structure
172 * NOTE: This function is called by schedule work
174 static void heci_bh_handler(struct work_struct *work)
176 struct iamt_heci_device *dev =
177 container_of(work, struct iamt_heci_device, work);
178 struct io_heci_list complete_list;
179 __s32 slots;
180 int rets;
181 struct heci_cb_private *cb_pos = NULL, *cb_next = NULL;
182 struct heci_file_private *file_ext;
183 int bus_message_received = 0;
184 struct task_struct *tsk;
186 DBG("function called after ISR to handle the interrupt processing.\n");
187 /* initialize our complete list */
188 spin_lock_bh(&dev->device_lock);
189 heci_initialize_list(&complete_list, dev);
190 dev->host_hw_state = read_heci_register(dev, H_CSR);
191 dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
193 /* check if ME wants a reset */
194 if (((dev->me_hw_state & ME_RDY_HRA) == 0)
195 && (dev->heci_state != HECI_RESETING)
196 && (dev->heci_state != HECI_INITIALIZING)) {
197 DBG("FW not ready.\n");
198 heci_reset(dev, 1);
199 spin_unlock_bh(&dev->device_lock);
200 return;
203 /* check if we need to start the dev */
204 if ((dev->host_hw_state & H_RDY) == 0) {
205 if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
206 DBG("we need to start the dev.\n");
207 dev->host_hw_state |= (H_IE | H_IG | H_RDY);
208 heci_set_csr_register(dev);
209 if (dev->heci_state == HECI_INITIALIZING) {
210 dev->recvd_msg = 1;
211 spin_unlock_bh(&dev->device_lock);
212 wake_up_interruptible(&dev->wait_recvd_msg);
213 return;
215 } else {
216 spin_unlock_bh(&dev->device_lock);
217 tsk = kthread_run(heci_task_initialize_clients,
218 dev, "heci_reinit");
219 if (IS_ERR(tsk)) {
220 int rc = PTR_ERR(tsk);
221 printk(KERN_WARNING "heci: Unable to"
222 "start the heci thread: %d\n", rc);
224 return;
226 } else {
227 DBG("enable interrupt FW not ready.\n");
228 heci_csr_enable_interrupts(dev);
229 spin_unlock_bh(&dev->device_lock);
230 return;
233 /* check slots avalable for reading */
234 slots = count_full_read_slots(dev);
235 DBG("slots =%08x extra_write_index =%08x.\n",
236 slots, dev->extra_write_index);
237 while ((slots > 0) && (!dev->extra_write_index)) {
238 DBG("slots =%08x extra_write_index =%08x.\n", slots,
239 dev->extra_write_index);
240 DBG("call heci_bh_read_handler.\n");
241 rets = heci_bh_read_handler(&complete_list, dev, &slots);
242 if (rets != 0)
243 goto end;
245 rets = heci_bh_write_handler(&complete_list, dev, &slots);
246 end:
247 DBG("end of bottom half function.\n");
248 dev->host_hw_state = read_heci_register(dev, H_CSR);
249 dev->host_buffer_is_empty = host_buffer_is_empty(dev);
251 if ((dev->host_hw_state & H_IS) == H_IS) {
252 /* acknowledge interrupt and disable interrupts */
253 heci_csr_disable_interrupts(dev);
255 PREPARE_WORK(&dev->work, heci_bh_handler);
256 DBG("schedule work the heci_bh_handler.\n");
257 rets = schedule_work(&dev->work);
258 if (!rets) {
259 printk(KERN_ERR "heci: schedule the heci_bh_handler"
260 " failed error=%x\n", rets);
262 } else {
263 heci_csr_enable_interrupts(dev);
266 if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
267 DBG("received waiting bus message\n");
268 bus_message_received = 1;
270 spin_unlock_bh(&dev->device_lock);
271 if (bus_message_received) {
272 DBG("wake up dev->wait_recvd_msg\n");
273 wake_up_interruptible(&dev->wait_recvd_msg);
274 bus_message_received = 0;
276 if ((complete_list.status != 0)
277 || list_empty(&complete_list.heci_cb.cb_list))
278 return;
281 list_for_each_entry_safe(cb_pos, cb_next,
282 &complete_list.heci_cb.cb_list, cb_list) {
283 file_ext = (struct heci_file_private *)cb_pos->file_private;
284 list_del(&cb_pos->cb_list);
285 if (file_ext != NULL) {
286 if (file_ext != &dev->iamthif_file_ext) {
287 DBG("completing call back.\n");
288 _heci_cmpl(file_ext, cb_pos);
289 cb_pos = NULL;
290 } else if (file_ext == &dev->iamthif_file_ext) {
291 _heci_cmpl_iamthif(dev, cb_pos);
299 * heci_bh_read_handler - bottom half read routine after ISR to
300 * handle the read processing.
302 * @cmpl_list: An instance of our list structure
303 * @dev: Device object for our driver
304 * @slots: slots to read.
306 * returns 0 on success, <0 on failure.
308 static int heci_bh_read_handler(struct io_heci_list *cmpl_list,
309 struct iamt_heci_device *dev,
310 __s32 *slots)
312 struct heci_msg_hdr *heci_hdr;
313 int ret = 0;
314 struct heci_file_private *file_pos = NULL;
315 struct heci_file_private *file_next = NULL;
317 if (!dev->rd_msg_hdr) {
318 dev->rd_msg_hdr = read_heci_register(dev, ME_CB_RW);
319 DBG("slots=%08x.\n", *slots);
320 (*slots)--;
321 DBG("slots=%08x.\n", *slots);
323 heci_hdr = (struct heci_msg_hdr *) &dev->rd_msg_hdr;
324 DBG("heci_hdr->length =%d\n", heci_hdr->length);
326 if ((heci_hdr->reserved) || !(dev->rd_msg_hdr)) {
327 DBG("corrupted message header.\n");
328 ret = -ECORRUPTED_MESSAGE_HEADER;
329 goto end;
332 if ((heci_hdr->host_addr) || (heci_hdr->me_addr)) {
333 list_for_each_entry_safe(file_pos, file_next,
334 &dev->file_list, link) {
335 DBG("list_for_each_entry_safe read host"
336 " client = %d, ME client = %d\n",
337 file_pos->host_client_id,
338 file_pos->me_client_id);
339 if ((file_pos->host_client_id == heci_hdr->host_addr)
340 && (file_pos->me_client_id == heci_hdr->me_addr))
341 break;
344 if (&file_pos->link == &dev->file_list) {
345 DBG("corrupted message header\n");
346 ret = -ECORRUPTED_MESSAGE_HEADER;
347 goto end;
350 if (((*slots) * sizeof(__u32)) < heci_hdr->length) {
351 DBG("we can't read the message slots=%08x.\n", *slots);
352 /* we can't read the message */
353 ret = -ERANGE;
354 goto end;
357 /* decide where to read the message too */
358 if (!heci_hdr->host_addr) {
359 DBG("call heci_bh_read_bus_message.\n");
360 heci_bh_read_bus_message(dev, heci_hdr);
361 DBG("end heci_bh_read_bus_message.\n");
362 } else if ((heci_hdr->host_addr == dev->iamthif_file_ext.host_client_id)
363 && (HECI_FILE_CONNECTED == dev->iamthif_file_ext.state)
364 && (dev->iamthif_state == HECI_IAMTHIF_READING)) {
365 DBG("call heci_bh_read_iamthif_message.\n");
366 DBG("heci_hdr->length =%d\n", heci_hdr->length);
367 ret = heci_bh_read_pthi_message(cmpl_list, dev, heci_hdr);
368 if (ret != 0)
369 goto end;
371 } else {
372 DBG("call heci_bh_read_client_message.\n");
373 ret = heci_bh_read_client_message(cmpl_list, dev, heci_hdr);
374 if (ret != 0)
375 goto end;
379 /* reset the number of slots and header */
380 *slots = count_full_read_slots(dev);
381 dev->rd_msg_hdr = 0;
383 if (*slots == -ESLOTS_OVERFLOW) {
384 /* overflow - reset */
385 DBG("reseting due to slots overflow.\n");
386 /* set the event since message has been read */
387 ret = -ERANGE;
388 goto end;
390 end:
391 return ret;
396 * heci_bh_read_bus_message - bottom half read routine after ISR to
397 * handle the read bus message cmd processing.
399 * @dev: Device object for our driver
400 * @heci_hdr: header of bus message
402 static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
403 struct heci_msg_hdr *heci_hdr)
405 struct heci_bus_message *heci_msg;
406 struct hbm_host_version_response *version_res;
407 struct hbm_client_connect_response *connect_res;
408 struct hbm_client_connect_response *disconnect_res;
409 struct hbm_flow_control *flow_control;
410 struct hbm_props_response *props_res;
411 struct hbm_host_enum_response *enum_res;
412 struct hbm_client_disconnect_request *disconnect_req;
413 struct hbm_host_stop_request *h_stop_req;
414 int i;
415 unsigned char *buffer;
417 /* read the message to our buffer */
418 buffer = (unsigned char *) dev->rd_msg_buf;
419 BUG_ON(heci_hdr->length >= sizeof(dev->rd_msg_buf));
420 heci_read_slots(dev, buffer, heci_hdr->length);
421 heci_msg = (struct heci_bus_message *) buffer;
423 switch (*(__u8 *) heci_msg) {
424 case HOST_START_RES_CMD:
425 version_res = (struct hbm_host_version_response *) heci_msg;
426 if (version_res->host_version_supported) {
427 dev->version.major_version = HBM_MAJOR_VERSION;
428 dev->version.minor_version = HBM_MINOR_VERSION;
429 } else {
430 dev->version = version_res->me_max_version;
432 dev->recvd_msg = 1;
433 DBG("host start response message received.\n");
434 break;
436 case CLIENT_CONNECT_RES_CMD:
437 connect_res =
438 (struct hbm_client_connect_response *) heci_msg;
439 heci_client_connect_response(dev, connect_res);
440 DBG("client connect response message received.\n");
441 wake_up(&dev->wait_recvd_msg);
442 break;
444 case CLIENT_DISCONNECT_RES_CMD:
445 disconnect_res =
446 (struct hbm_client_connect_response *) heci_msg;
447 heci_client_disconnect_response(dev, disconnect_res);
448 DBG("client disconnect response message received.\n");
449 wake_up(&dev->wait_recvd_msg);
450 break;
452 case HECI_FLOW_CONTROL_CMD:
453 flow_control = (struct hbm_flow_control *) heci_msg;
454 heci_client_flow_control_response(dev, flow_control);
455 DBG("client flow control response message received.\n");
456 break;
458 case HOST_CLIENT_PROPERTEIS_RES_CMD:
459 props_res = (struct hbm_props_response *) heci_msg;
460 if (props_res->status != 0) {
461 BUG();
462 break;
464 for (i = 0; i < dev->num_heci_me_clients; i++) {
465 if (dev->me_clients[i].client_id ==
466 props_res->address) {
467 dev->me_clients[i].props =
468 props_res->client_properties;
469 break;
473 dev->recvd_msg = 1;
474 break;
476 case HOST_ENUM_RES_CMD:
477 enum_res = (struct hbm_host_enum_response *) heci_msg;
478 memcpy(dev->heci_me_clients, enum_res->valid_addresses, 32);
479 dev->recvd_msg = 1;
480 break;
482 case HOST_STOP_RES_CMD:
483 dev->heci_state = HECI_DISABLED;
484 DBG("reseting because of FW stop response.\n");
485 heci_reset(dev, 1);
486 break;
488 case CLIENT_DISCONNECT_REQ_CMD:
489 /* search for client */
490 disconnect_req =
491 (struct hbm_client_disconnect_request *) heci_msg;
492 heci_client_disconnect_request(dev, disconnect_req);
493 break;
495 case ME_STOP_REQ_CMD:
496 /* prepare stop request */
497 heci_hdr = (struct heci_msg_hdr *) &dev->ext_msg_buf[0];
498 heci_hdr->host_addr = 0;
499 heci_hdr->me_addr = 0;
500 heci_hdr->length = sizeof(struct hbm_host_stop_request);
501 heci_hdr->msg_complete = 1;
502 heci_hdr->reserved = 0;
503 h_stop_req =
504 (struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
505 memset(h_stop_req, 0, sizeof(struct hbm_host_stop_request));
506 h_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
507 h_stop_req->reason = DRIVER_STOP_REQUEST;
508 h_stop_req->reserved[0] = 0;
509 h_stop_req->reserved[1] = 0;
510 dev->extra_write_index = 2;
511 break;
513 default:
514 BUG();
515 break;
521 * heci_bh_read_pthi_message - bottom half read routine after ISR to
522 * handle the read pthi message data processing.
524 * @complete_list: An instance of our list structure
525 * @dev: Device object for our driver
526 * @heci_hdr: header of pthi message
528 * returns 0 on success, <0 on failure.
530 static int heci_bh_read_pthi_message(struct io_heci_list *complete_list,
531 struct iamt_heci_device *dev,
532 struct heci_msg_hdr *heci_hdr)
534 struct heci_file_private *file_ext;
535 struct heci_cb_private *priv_cb;
536 unsigned char *buffer;
538 BUG_ON(heci_hdr->me_addr != dev->iamthif_file_ext.me_client_id);
539 BUG_ON(dev->iamthif_state != HECI_IAMTHIF_READING);
541 buffer = (unsigned char *) (dev->iamthif_msg_buf +
542 dev->iamthif_msg_buf_index);
543 BUG_ON(sizeof(dev->iamthif_msg_buf) <
544 (dev->iamthif_msg_buf_index + heci_hdr->length));
546 heci_read_slots(dev, buffer, heci_hdr->length);
548 dev->iamthif_msg_buf_index += heci_hdr->length;
550 if (!(heci_hdr->msg_complete))
551 return 0;
553 DBG("pthi_message_buffer_index=%d\n", heci_hdr->length);
554 DBG("completed pthi read.\n ");
555 if (!dev->iamthif_current_cb)
556 return -ENODEV;
558 priv_cb = dev->iamthif_current_cb;
559 dev->iamthif_current_cb = NULL;
561 file_ext = (struct heci_file_private *)priv_cb->file_private;
562 if (!file_ext)
563 return -ENODEV;
565 dev->iamthif_stall_timer = 0;
566 priv_cb->information = dev->iamthif_msg_buf_index;
567 priv_cb->read_time = get_seconds();
568 if ((dev->iamthif_ioctl) && (file_ext == &dev->iamthif_file_ext)) {
569 /* found the iamthif cb */
570 DBG("complete the pthi read cb.\n ");
571 if (&dev->iamthif_file_ext) {
572 DBG("add the pthi read cb to complete.\n ");
573 list_add_tail(&priv_cb->cb_list,
574 &complete_list->heci_cb.cb_list);
577 return 0;
581 * _heci_bh_state_ok - check if heci header matches file private data
583 * @file_ext: private data of the file object
584 * @heci_hdr: header of heci client message
586 * returns !=0 if matches, 0 if no match.
588 static int _heci_bh_state_ok(struct heci_file_private *file_ext,
589 struct heci_msg_hdr *heci_hdr)
591 return ((file_ext->host_client_id == heci_hdr->host_addr)
592 && (file_ext->me_client_id == heci_hdr->me_addr)
593 && (file_ext->state == HECI_FILE_CONNECTED)
594 && (HECI_READ_COMPLETE != file_ext->reading_state));
598 * heci_bh_read_client_message - bottom half read routine after ISR to
599 * handle the read heci client message data processing.
601 * @complete_list: An instance of our list structure
602 * @dev: Device object for our driver
603 * @heci_hdr: header of heci client message
605 * returns 0 on success, <0 on failure.
607 static int heci_bh_read_client_message(struct io_heci_list *complete_list,
608 struct iamt_heci_device *dev,
609 struct heci_msg_hdr *heci_hdr)
611 struct heci_file_private *file_ext;
612 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
613 unsigned char *buffer = NULL;
615 DBG("start client msg\n");
616 if (!((dev->read_list.status == 0) &&
617 !list_empty(&dev->read_list.heci_cb.cb_list)))
618 goto quit;
620 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
621 &dev->read_list.heci_cb.cb_list, cb_list) {
622 file_ext = (struct heci_file_private *)
623 priv_cb_pos->file_private;
624 if ((file_ext != NULL) &&
625 (_heci_bh_state_ok(file_ext, heci_hdr))) {
626 spin_lock(&file_ext->read_io_lock);
627 file_ext->reading_state = HECI_READING;
628 buffer = (unsigned char *)
629 (priv_cb_pos->response_buffer.data +
630 priv_cb_pos->information);
631 BUG_ON(priv_cb_pos->response_buffer.size <
632 heci_hdr->length +
633 priv_cb_pos->information);
635 if (priv_cb_pos->response_buffer.size <
636 heci_hdr->length +
637 priv_cb_pos->information) {
638 DBG("message overflow.\n");
639 list_del(&priv_cb_pos->cb_list);
640 spin_unlock(&file_ext->read_io_lock);
641 return -ENOMEM;
643 if (buffer) {
644 heci_read_slots(dev, buffer,
645 heci_hdr->length);
647 priv_cb_pos->information += heci_hdr->length;
648 if (heci_hdr->msg_complete) {
649 file_ext->status = 0;
650 list_del(&priv_cb_pos->cb_list);
651 spin_unlock(&file_ext->read_io_lock);
652 DBG("completed read host client = %d,"
653 "ME client = %d, "
654 "data length = %lu\n",
655 file_ext->host_client_id,
656 file_ext->me_client_id,
657 priv_cb_pos->information);
659 *(priv_cb_pos->response_buffer.data +
660 priv_cb_pos->information) = '\0';
661 DBG("priv_cb_pos->res_buffer - %s\n",
662 priv_cb_pos->response_buffer.data);
663 list_add_tail(&priv_cb_pos->cb_list,
664 &complete_list->heci_cb.cb_list);
665 } else {
666 spin_unlock(&file_ext->read_io_lock);
669 break;
674 quit:
675 DBG("message read\n");
676 if (!buffer) {
677 heci_read_slots(dev, (unsigned char *) dev->rd_msg_buf,
678 heci_hdr->length);
679 DBG("discarding message, header=%08x.\n",
680 *(__u32 *) dev->rd_msg_buf);
683 return 0;
687 * _heci_bh_iamthif_read - prepare to read iamthif data.
689 * @dev: Device object for our driver.
690 * @slots: free slots.
692 * returns 0, OK; otherwise, error.
694 static int _heci_bh_iamthif_read(struct iamt_heci_device *dev, __s32 *slots)
697 if (((*slots) * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr)
698 + sizeof(struct hbm_flow_control))) {
699 *slots -= (sizeof(struct heci_msg_hdr) +
700 sizeof(struct hbm_flow_control) + 3) / 4;
701 if (!heci_send_flow_control(dev, &dev->iamthif_file_ext)) {
702 DBG("iamthif flow control failed\n");
703 } else {
704 DBG("iamthif flow control success\n");
705 dev->iamthif_state = HECI_IAMTHIF_READING;
706 dev->iamthif_flow_control_pending = 0;
707 dev->iamthif_msg_buf_index = 0;
708 dev->iamthif_msg_buf_size = 0;
709 dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
710 dev->host_buffer_is_empty = host_buffer_is_empty(dev);
712 return 0;
713 } else {
714 return -ECOMPLETE_MESSAGE;
719 * _heci_bh_close - process close related operation.
721 * @dev: Device object for our driver.
722 * @slots: free slots.
723 * @priv_cb_pos: callback block.
724 * @file_ext: private data of the file object.
725 * @cmpl_list: complete list.
727 * returns 0, OK; otherwise, error.
729 static int _heci_bh_close(struct iamt_heci_device *dev, __s32 *slots,
730 struct heci_cb_private *priv_cb_pos,
731 struct heci_file_private *file_ext,
732 struct io_heci_list *cmpl_list)
734 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
735 sizeof(struct hbm_client_disconnect_request))) {
736 *slots -= (sizeof(struct heci_msg_hdr) +
737 sizeof(struct hbm_client_disconnect_request) + 3) / 4;
739 if (!heci_disconnect(dev, file_ext)) {
740 file_ext->status = 0;
741 priv_cb_pos->information = 0;
742 list_move_tail(&priv_cb_pos->cb_list,
743 &cmpl_list->heci_cb.cb_list);
744 return -ECOMPLETE_MESSAGE;
745 } else {
746 file_ext->state = HECI_FILE_DISCONNECTING;
747 file_ext->status = 0;
748 priv_cb_pos->information = 0;
749 list_move_tail(&priv_cb_pos->cb_list,
750 &dev->ctrl_rd_list.heci_cb.cb_list);
751 file_ext->timer_count = HECI_CONNECT_TIMEOUT;
753 } else {
754 /* return the cancel routine */
755 return -ECORRUPTED_MESSAGE_HEADER;
758 return 0;
762 * _heci_hb_close - process read related operation.
764 * @dev: Device object for our driver.
765 * @slots: free slots.
766 * @priv_cb_pos: callback block.
767 * @file_ext: private data of the file object.
768 * @cmpl_list: complete list.
770 * returns 0, OK; otherwise, error.
772 static int _heci_bh_read(struct iamt_heci_device *dev, __s32 *slots,
773 struct heci_cb_private *priv_cb_pos,
774 struct heci_file_private *file_ext,
775 struct io_heci_list *cmpl_list)
777 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
778 sizeof(struct hbm_flow_control))) {
779 *slots -= (sizeof(struct heci_msg_hdr) +
780 sizeof(struct hbm_flow_control) + 3) / 4;
781 if (!heci_send_flow_control(dev, file_ext)) {
782 file_ext->status = -ENODEV;
783 priv_cb_pos->information = 0;
784 list_move_tail(&priv_cb_pos->cb_list,
785 &cmpl_list->heci_cb.cb_list);
786 return -ENODEV;
787 } else {
788 list_move_tail(&priv_cb_pos->cb_list,
789 &dev->read_list.heci_cb.cb_list);
791 } else {
792 /* return the cancel routine */
793 list_del(&priv_cb_pos->cb_list);
794 return -ECORRUPTED_MESSAGE_HEADER;
797 return 0;
802 * _heci_bh_ioctl - process ioctl related operation.
804 * @dev: Device object for our driver.
805 * @slots: free slots.
806 * @priv_cb_pos: callback block.
807 * @file_ext: private data of the file object.
808 * @cmpl_list: complete list.
810 * returns 0, OK; otherwise, error.
812 static int _heci_bh_ioctl(struct iamt_heci_device *dev, __s32 *slots,
813 struct heci_cb_private *priv_cb_pos,
814 struct heci_file_private *file_ext,
815 struct io_heci_list *cmpl_list)
817 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
818 sizeof(struct hbm_client_connect_request))) {
819 file_ext->state = HECI_FILE_CONNECTING;
820 *slots -= (sizeof(struct heci_msg_hdr) +
821 sizeof(struct hbm_client_connect_request) + 3) / 4;
822 if (!heci_connect(dev, file_ext)) {
823 file_ext->status = -ENODEV;
824 priv_cb_pos->information = 0;
825 list_del(&priv_cb_pos->cb_list);
826 return -ENODEV;
827 } else {
828 list_move_tail(&priv_cb_pos->cb_list,
829 &dev->ctrl_rd_list.heci_cb.cb_list);
830 file_ext->timer_count = HECI_CONNECT_TIMEOUT;
832 } else {
833 /* return the cancel routine */
834 list_del(&priv_cb_pos->cb_list);
835 return -ECORRUPTED_MESSAGE_HEADER;
838 return 0;
842 * _heci_bh_cmpl - process completed and no-iamthif operation.
844 * @dev: Device object for our driver.
845 * @slots: free slots.
846 * @priv_cb_pos: callback block.
847 * @file_ext: private data of the file object.
848 * @cmpl_list: complete list.
850 * returns 0, OK; otherwise, error.
852 static int _heci_bh_cmpl(struct iamt_heci_device *dev, __s32 *slots,
853 struct heci_cb_private *priv_cb_pos,
854 struct heci_file_private *file_ext,
855 struct io_heci_list *cmpl_list)
857 struct heci_msg_hdr *heci_hdr;
859 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
860 (priv_cb_pos->request_buffer.size -
861 priv_cb_pos->information))) {
862 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
863 heci_hdr->host_addr = file_ext->host_client_id;
864 heci_hdr->me_addr = file_ext->me_client_id;
865 heci_hdr->length = ((priv_cb_pos->request_buffer.size) -
866 (priv_cb_pos->information));
867 heci_hdr->msg_complete = 1;
868 heci_hdr->reserved = 0;
869 DBG("priv_cb_pos->request_buffer.size =%d"
870 "heci_hdr->msg_complete= %d\n",
871 priv_cb_pos->request_buffer.size,
872 heci_hdr->msg_complete);
873 DBG("priv_cb_pos->information =%lu\n",
874 priv_cb_pos->information);
875 DBG("heci_hdr->length =%d\n",
876 heci_hdr->length);
877 *slots -= (sizeof(struct heci_msg_hdr) +
878 heci_hdr->length + 3) / 4;
879 if (!heci_write_message(dev, heci_hdr,
880 (unsigned char *)
881 (priv_cb_pos->request_buffer.data +
882 priv_cb_pos->information),
883 heci_hdr->length)) {
884 file_ext->status = -ENODEV;
885 list_move_tail(&priv_cb_pos->cb_list,
886 &cmpl_list->heci_cb.cb_list);
887 return -ENODEV;
888 } else {
889 flow_ctrl_reduce(dev, file_ext);
890 file_ext->status = 0;
891 priv_cb_pos->information += heci_hdr->length;
892 list_move_tail(&priv_cb_pos->cb_list,
893 &dev->write_waiting_list.heci_cb.cb_list);
895 } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
896 /* buffer is still empty */
897 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
898 heci_hdr->host_addr = file_ext->host_client_id;
899 heci_hdr->me_addr = file_ext->me_client_id;
900 heci_hdr->length =
901 (*slots * sizeof(__u32)) - sizeof(struct heci_msg_hdr);
902 heci_hdr->msg_complete = 0;
903 heci_hdr->reserved = 0;
905 (*slots) -= (sizeof(struct heci_msg_hdr) +
906 heci_hdr->length + 3) / 4;
907 if (!heci_write_message(dev, heci_hdr,
908 (unsigned char *)
909 (priv_cb_pos->request_buffer.data +
910 priv_cb_pos->information),
911 heci_hdr->length)) {
912 file_ext->status = -ENODEV;
913 list_move_tail(&priv_cb_pos->cb_list,
914 &cmpl_list->heci_cb.cb_list);
915 return -ENODEV;
916 } else {
917 priv_cb_pos->information += heci_hdr->length;
918 DBG("priv_cb_pos->request_buffer.size =%d"
919 " heci_hdr->msg_complete= %d\n",
920 priv_cb_pos->request_buffer.size,
921 heci_hdr->msg_complete);
922 DBG("priv_cb_pos->information =%lu\n",
923 priv_cb_pos->information);
924 DBG("heci_hdr->length =%d\n", heci_hdr->length);
926 return -ECOMPLETE_MESSAGE;
927 } else {
928 return -ECORRUPTED_MESSAGE_HEADER;
931 return 0;
935 * _heci_bh_cmpl_iamthif - process completed iamthif operation.
937 * @dev: Device object for our driver.
938 * @slots: free slots.
939 * @priv_cb_pos: callback block.
940 * @file_ext: private data of the file object.
941 * @cmpl_list: complete list.
943 * returns 0, OK; otherwise, error.
945 static int _heci_bh_cmpl_iamthif(struct iamt_heci_device *dev, __s32 *slots,
946 struct heci_cb_private *priv_cb_pos,
947 struct heci_file_private *file_ext,
948 struct io_heci_list *cmpl_list)
950 struct heci_msg_hdr *heci_hdr;
952 if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
953 dev->iamthif_msg_buf_size -
954 dev->iamthif_msg_buf_index)) {
955 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
956 heci_hdr->host_addr = file_ext->host_client_id;
957 heci_hdr->me_addr = file_ext->me_client_id;
958 heci_hdr->length = dev->iamthif_msg_buf_size -
959 dev->iamthif_msg_buf_index;
960 heci_hdr->msg_complete = 1;
961 heci_hdr->reserved = 0;
963 *slots -= (sizeof(struct heci_msg_hdr) +
964 heci_hdr->length + 3) / 4;
966 if (!heci_write_message(dev, heci_hdr,
967 (dev->iamthif_msg_buf +
968 dev->iamthif_msg_buf_index),
969 heci_hdr->length)) {
970 dev->iamthif_state = HECI_IAMTHIF_IDLE;
971 file_ext->status = -ENODEV;
972 list_del(&priv_cb_pos->cb_list);
973 return -ENODEV;
974 } else {
975 flow_ctrl_reduce(dev, file_ext);
976 dev->iamthif_msg_buf_index += heci_hdr->length;
977 priv_cb_pos->information = dev->iamthif_msg_buf_index;
978 file_ext->status = 0;
979 dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL;
980 dev->iamthif_flow_control_pending = 1;
981 /* save iamthif cb sent to pthi client */
982 dev->iamthif_current_cb = priv_cb_pos;
983 list_move_tail(&priv_cb_pos->cb_list,
984 &dev->write_waiting_list.heci_cb.cb_list);
987 } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
988 /* buffer is still empty */
989 heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
990 heci_hdr->host_addr = file_ext->host_client_id;
991 heci_hdr->me_addr = file_ext->me_client_id;
992 heci_hdr->length =
993 (*slots * sizeof(__u32)) - sizeof(struct heci_msg_hdr);
994 heci_hdr->msg_complete = 0;
995 heci_hdr->reserved = 0;
997 *slots -= (sizeof(struct heci_msg_hdr) +
998 heci_hdr->length + 3) / 4;
1000 if (!heci_write_message(dev, heci_hdr,
1001 (dev->iamthif_msg_buf +
1002 dev->iamthif_msg_buf_index),
1003 heci_hdr->length)) {
1004 file_ext->status = -ENODEV;
1005 list_del(&priv_cb_pos->cb_list);
1006 } else {
1007 dev->iamthif_msg_buf_index += heci_hdr->length;
1009 return -ECOMPLETE_MESSAGE;
1010 } else {
1011 return -ECORRUPTED_MESSAGE_HEADER;
1014 return 0;
1018 * heci_bh_write_handler - bottom half write routine after
1019 * ISR to handle the write processing.
1021 * @cmpl_list: An instance of our list structure
1022 * @dev: Device object for our driver
1023 * @slots: slots to write.
1025 * returns 0 on success, <0 on failure.
1027 static int heci_bh_write_handler(struct io_heci_list *cmpl_list,
1028 struct iamt_heci_device *dev,
1029 __s32 *slots)
1032 struct heci_file_private *file_ext;
1033 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1034 struct io_heci_list *list;
1035 int ret;
1037 if (!host_buffer_is_empty(dev)) {
1038 DBG("host buffer is not empty.\n");
1039 return 0;
1041 dev->write_hang = -1;
1042 *slots = count_empty_write_slots(dev);
1043 /* complete all waiting for write CB */
1044 DBG("complete all waiting for write cb.\n");
1046 list = &dev->write_waiting_list;
1047 if ((list->status == 0)
1048 && !list_empty(&list->heci_cb.cb_list)) {
1049 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1050 &list->heci_cb.cb_list, cb_list) {
1051 file_ext = (struct heci_file_private *)
1052 priv_cb_pos->file_private;
1053 if (file_ext != NULL) {
1054 file_ext->status = 0;
1055 list_del(&priv_cb_pos->cb_list);
1056 if ((HECI_WRITING == file_ext->writing_state) &&
1057 (priv_cb_pos->major_file_operations ==
1058 HECI_WRITING) &&
1059 (file_ext != &dev->iamthif_file_ext)) {
1060 DBG("HECI WRITE COMPLETE\n");
1061 file_ext->writing_state =
1062 HECI_WRITE_COMPLETE;
1063 list_add_tail(&priv_cb_pos->cb_list,
1064 &cmpl_list->heci_cb.cb_list);
1066 if (file_ext == &dev->iamthif_file_ext) {
1067 DBG("check iamthif flow control.\n");
1068 if (dev->iamthif_flow_control_pending) {
1069 ret = _heci_bh_iamthif_read(dev,
1070 slots);
1071 if (ret != 0)
1072 return ret;
1080 if ((dev->stop) && (!dev->wd_pending)) {
1081 dev->wd_stoped = 1;
1082 wake_up_interruptible(&dev->wait_stop_wd);
1083 return 0;
1086 if (dev->extra_write_index != 0) {
1087 DBG("extra_write_index =%d.\n", dev->extra_write_index);
1088 heci_write_message(dev,
1089 (struct heci_msg_hdr *) &dev->ext_msg_buf[0],
1090 (unsigned char *) &dev->ext_msg_buf[1],
1091 (dev->extra_write_index - 1) * sizeof(__u32));
1092 *slots -= dev->extra_write_index;
1093 dev->extra_write_index = 0;
1095 if (dev->heci_state == HECI_ENABLED) {
1096 if ((dev->wd_pending)
1097 && flow_ctrl_creds(dev, &dev->wd_file_ext)) {
1098 if (!heci_send_wd(dev))
1099 DBG("wd send failed.\n");
1100 else
1101 flow_ctrl_reduce(dev, &dev->wd_file_ext);
1103 dev->wd_pending = 0;
1105 if (dev->wd_timeout != 0) {
1106 *slots -= (sizeof(struct heci_msg_hdr) +
1107 HECI_START_WD_DATA_SIZE + 3) / 4;
1108 dev->wd_due_counter = 2;
1109 } else {
1110 *slots -= (sizeof(struct heci_msg_hdr) +
1111 HECI_WD_PARAMS_SIZE + 3) / 4;
1112 dev->wd_due_counter = 0;
1117 if (dev->stop)
1118 return ~ENODEV;
1120 /* complete control write list CB */
1121 if (dev->ctrl_wr_list.status == 0) {
1122 /* complete control write list CB */
1123 DBG("complete control write list cb.\n");
1124 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1125 &dev->ctrl_wr_list.heci_cb.cb_list, cb_list) {
1126 file_ext = (struct heci_file_private *)
1127 priv_cb_pos->file_private;
1128 if (file_ext == NULL) {
1129 list_del(&priv_cb_pos->cb_list);
1130 return -ENODEV;
1132 switch (priv_cb_pos->major_file_operations) {
1133 case HECI_CLOSE:
1134 /* send disconnect message */
1135 ret = _heci_bh_close(dev, slots,
1136 priv_cb_pos,
1137 file_ext, cmpl_list);
1138 if (ret != 0)
1139 return ret;
1141 break;
1142 case HECI_READ:
1143 /* send flow control message */
1144 ret = _heci_bh_read(dev, slots,
1145 priv_cb_pos,
1146 file_ext, cmpl_list);
1147 if (ret != 0)
1148 return ret;
1150 break;
1151 case HECI_IOCTL:
1152 /* connect message */
1153 if (!other_client_is_connecting(dev, file_ext))
1154 continue;
1155 ret = _heci_bh_ioctl(dev, slots,
1156 priv_cb_pos,
1157 file_ext, cmpl_list);
1158 if (ret != 0)
1159 return ret;
1161 break;
1163 default:
1164 BUG();
1169 /* complete write list CB */
1170 if ((dev->write_list.status == 0)
1171 && !list_empty(&dev->write_list.heci_cb.cb_list)) {
1172 DBG("complete write list cb.\n");
1173 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1174 &dev->write_list.heci_cb.cb_list, cb_list) {
1175 file_ext = (struct heci_file_private *)
1176 priv_cb_pos->file_private;
1178 if (file_ext != NULL) {
1179 if (file_ext != &dev->iamthif_file_ext) {
1180 if (!flow_ctrl_creds(dev, file_ext)) {
1181 DBG("No flow control"
1182 " credentials for client"
1183 " %d, not sending.\n",
1184 file_ext->host_client_id);
1185 continue;
1187 ret = _heci_bh_cmpl(dev, slots,
1188 priv_cb_pos,
1189 file_ext,
1190 cmpl_list);
1191 if (ret != 0)
1192 return ret;
1194 } else if (file_ext == &dev->iamthif_file_ext) {
1195 /* IAMTHIF IOCTL */
1196 DBG("complete pthi write cb.\n");
1197 if (!flow_ctrl_creds(dev, file_ext)) {
1198 DBG("No flow control"
1199 " credentials for pthi"
1200 " client %d.\n",
1201 file_ext->host_client_id);
1202 continue;
1204 ret = _heci_bh_cmpl_iamthif(dev, slots,
1205 priv_cb_pos,
1206 file_ext,
1207 cmpl_list);
1208 if (ret != 0)
1209 return ret;
1216 return 0;
1221 * is_treat_specially_client - check if the message belong
1222 * to the file private data.
1224 * @file_ext: private data of the file object
1225 * @rs: connect response bus message
1226 * @dev: Device object for our driver
1228 * returns 0 on success, <0 on failure.
1230 static int is_treat_specially_client(struct heci_file_private *file_ext,
1231 struct hbm_client_connect_response *rs)
1233 int ret = 0;
1235 if ((file_ext->host_client_id == rs->host_addr) &&
1236 (file_ext->me_client_id == rs->me_addr)) {
1237 if (rs->status == 0) {
1238 DBG("client connect status = 0x%08x.\n", rs->status);
1239 file_ext->state = HECI_FILE_CONNECTED;
1240 file_ext->status = 0;
1241 } else {
1242 DBG("client connect status = 0x%08x.\n", rs->status);
1243 file_ext->state = HECI_FILE_DISCONNECTED;
1244 file_ext->status = -ENODEV;
1246 ret = 1;
1248 DBG("client state = %d.\n", file_ext->state);
1249 return ret;
1253 * heci_client_connect_response - connect response bh routine
1255 * @dev: Device object for our driver
1256 * @rs: connect response bus message
1258 static void heci_client_connect_response(struct iamt_heci_device *dev,
1259 struct hbm_client_connect_response *rs)
1262 struct heci_file_private *file_ext;
1263 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1265 /* if WD or iamthif client treat specially */
1267 if ((is_treat_specially_client(&(dev->wd_file_ext), rs)) ||
1268 (is_treat_specially_client(&(dev->iamthif_file_ext), rs)))
1269 return;
1271 if (dev->ctrl_rd_list.status == 0
1272 && !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) {
1273 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1274 &dev->ctrl_rd_list.heci_cb.cb_list, cb_list) {
1275 file_ext = (struct heci_file_private *)
1276 priv_cb_pos->file_private;
1277 if (file_ext == NULL) {
1278 list_del(&priv_cb_pos->cb_list);
1279 return;
1281 if (HECI_IOCTL == priv_cb_pos->major_file_operations) {
1282 if (is_treat_specially_client(file_ext, rs)) {
1283 list_del(&priv_cb_pos->cb_list);
1284 file_ext->status = 0;
1285 file_ext->timer_count = 0;
1286 break;
1294 * heci_client_disconnect_response - disconnect response bh routine
1296 * @dev: Device object for our driver
1297 * @rs: disconnect response bus message
1299 static void heci_client_disconnect_response(struct iamt_heci_device *dev,
1300 struct hbm_client_connect_response *rs)
1302 struct heci_file_private *file_ext;
1303 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1305 if (dev->ctrl_rd_list.status == 0
1306 && !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) {
1307 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1308 &dev->ctrl_rd_list.heci_cb.cb_list, cb_list) {
1309 file_ext = (struct heci_file_private *)
1310 priv_cb_pos->file_private;
1312 if (file_ext == NULL) {
1313 list_del(&priv_cb_pos->cb_list);
1314 return;
1317 DBG("list_for_each_entry_safe in ctrl_rd_list.\n");
1318 if ((file_ext->host_client_id == rs->host_addr) &&
1319 (file_ext->me_client_id == rs->me_addr)) {
1321 list_del(&priv_cb_pos->cb_list);
1322 if (rs->status == 0) {
1323 file_ext->state =
1324 HECI_FILE_DISCONNECTED;
1327 file_ext->status = 0;
1328 file_ext->timer_count = 0;
1329 break;
1336 * same_flow_addr - tell they have same address.
1338 * @file: private data of the file object.
1339 * @flow: flow control.
1341 * returns !=0, same; 0,not.
1343 static int same_flow_addr(struct heci_file_private *file,
1344 struct hbm_flow_control *flow)
1346 return ((file->host_client_id == flow->host_addr)
1347 && (file->me_client_id == flow->me_addr));
1351 * add_single_flow_creds - add single buffer credentials.
1353 * @file: private data ot the file object.
1354 * @flow: flow control.
1356 static void add_single_flow_creds(struct iamt_heci_device *dev,
1357 struct hbm_flow_control *flow)
1359 struct heci_me_client *client;
1360 int i;
1362 for (i = 0; i < dev->num_heci_me_clients; i++) {
1363 client = &dev->me_clients[i];
1364 if ((client != NULL) &&
1365 (flow->me_addr == client->client_id)) {
1366 if (client->props.single_recv_buf != 0) {
1367 client->flow_ctrl_creds++;
1368 DBG("recv flow ctrl msg ME %d (single).\n",
1369 flow->me_addr);
1370 DBG("flow control credentials=%d.\n",
1371 client->flow_ctrl_creds);
1372 } else {
1373 BUG(); /* error in flow control */
1380 * heci_client_flow_control_response - flow control response bh routine
1382 * @dev: Device object for our driver
1383 * @flow_control: flow control response bus message
1385 static void heci_client_flow_control_response(struct iamt_heci_device *dev,
1386 struct hbm_flow_control *flow_control)
1388 struct heci_file_private *file_pos = NULL;
1389 struct heci_file_private *file_next = NULL;
1391 if (flow_control->host_addr == 0) {
1392 /* single receive buffer */
1393 add_single_flow_creds(dev, flow_control);
1394 } else {
1395 /* normal connection */
1396 list_for_each_entry_safe(file_pos, file_next,
1397 &dev->file_list, link) {
1398 DBG("list_for_each_entry_safe in file_list\n");
1400 DBG("file_ext of host client %d ME client %d.\n",
1401 file_pos->host_client_id,
1402 file_pos->me_client_id);
1403 DBG("flow ctrl msg for host %d ME %d.\n",
1404 flow_control->host_addr,
1405 flow_control->me_addr);
1406 if (same_flow_addr(file_pos, flow_control)) {
1407 DBG("recv ctrl msg for host %d ME %d.\n",
1408 flow_control->host_addr,
1409 flow_control->me_addr);
1410 file_pos->flow_ctrl_creds++;
1411 DBG("flow control credentials=%d.\n",
1412 file_pos->flow_ctrl_creds);
1413 break;
1420 * same_disconn_addr - tell they have same address
1422 * @file: private data of the file object.
1423 * @disconn: disconnection request.
1425 * returns !=0, same; 0,not.
1427 static int same_disconn_addr(struct heci_file_private *file,
1428 struct hbm_client_disconnect_request *disconn)
1430 return ((file->host_client_id == disconn->host_addr)
1431 && (file->me_client_id == disconn->me_addr));
1435 * heci_client_disconnect_request - disconnect request bh routine
1437 * @dev: Device object for our driver.
1438 * @disconnect_req: disconnect request bus message.
1440 static void heci_client_disconnect_request(struct iamt_heci_device *dev,
1441 struct hbm_client_disconnect_request *disconnect_req)
1443 struct heci_msg_hdr *heci_hdr;
1444 struct hbm_client_connect_response *disconnect_res;
1445 struct heci_file_private *file_pos = NULL;
1446 struct heci_file_private *file_next = NULL;
1448 list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) {
1449 if (same_disconn_addr(file_pos, disconnect_req)) {
1450 DBG("disconnect request host client %d ME client %d.\n",
1451 disconnect_req->host_addr,
1452 disconnect_req->me_addr);
1453 file_pos->state = HECI_FILE_DISCONNECTED;
1454 file_pos->timer_count = 0;
1455 if (file_pos == &dev->wd_file_ext) {
1456 dev->wd_due_counter = 0;
1457 dev->wd_pending = 0;
1458 } else if (file_pos == &dev->iamthif_file_ext)
1459 dev->iamthif_timer = 0;
1461 /* prepare disconnect response */
1462 heci_hdr =
1463 (struct heci_msg_hdr *) &dev->ext_msg_buf[0];
1464 heci_hdr->host_addr = 0;
1465 heci_hdr->me_addr = 0;
1466 heci_hdr->length =
1467 sizeof(struct hbm_client_connect_response);
1468 heci_hdr->msg_complete = 1;
1469 heci_hdr->reserved = 0;
1471 disconnect_res =
1472 (struct hbm_client_connect_response *)
1473 &dev->ext_msg_buf[1];
1474 disconnect_res->host_addr = file_pos->host_client_id;
1475 disconnect_res->me_addr = file_pos->me_client_id;
1476 *(__u8 *) (&disconnect_res->cmd) =
1477 CLIENT_DISCONNECT_RES_CMD;
1478 disconnect_res->status = 0;
1479 dev->extra_write_index = 2;
1480 break;
1486 * heci_timer - timer function.
1488 * @data: pointer to the device structure
1490 * NOTE: This function is called by timer interrupt work
1492 void heci_wd_timer(unsigned long data)
1494 struct iamt_heci_device *dev = (struct iamt_heci_device *) data;
1496 DBG("send watchdog.\n");
1497 spin_lock_bh(&dev->device_lock);
1498 if (dev->heci_state != HECI_ENABLED) {
1499 mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
1500 spin_unlock_bh(&dev->device_lock);
1501 return;
1503 if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) {
1504 mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
1505 spin_unlock_bh(&dev->device_lock);
1506 return;
1508 /* Watchdog */
1509 if ((dev->wd_due_counter != 0) && (dev->wd_bypass == 0)) {
1510 if (--dev->wd_due_counter == 0) {
1511 if (dev->host_buffer_is_empty &&
1512 flow_ctrl_creds(dev, &dev->wd_file_ext)) {
1513 dev->host_buffer_is_empty = 0;
1514 if (!heci_send_wd(dev)) {
1515 DBG("wd send failed.\n");
1516 } else {
1517 flow_ctrl_reduce(dev,
1518 &dev->wd_file_ext);
1521 if (dev->wd_timeout != 0)
1522 dev->wd_due_counter = 2;
1523 else
1524 dev->wd_due_counter = 0;
1526 } else
1527 dev->wd_pending = 1;
1531 if (dev->iamthif_stall_timer != 0) {
1532 if (--dev->iamthif_stall_timer == 0) {
1533 DBG("reseting because of hang to PTHI.\n");
1534 heci_reset(dev, 1);
1535 dev->iamthif_msg_buf_size = 0;
1536 dev->iamthif_msg_buf_index = 0;
1537 dev->iamthif_canceled = 0;
1538 dev->iamthif_ioctl = 1;
1539 dev->iamthif_state = HECI_IAMTHIF_IDLE;
1540 dev->iamthif_timer = 0;
1541 spin_unlock_bh(&dev->device_lock);
1543 if (dev->iamthif_current_cb)
1544 heci_free_cb_private(dev->iamthif_current_cb);
1546 spin_lock_bh(&dev->device_lock);
1547 dev->iamthif_file_object = NULL;
1548 dev->iamthif_current_cb = NULL;
1549 run_next_iamthif_cmd(dev);
1552 mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
1553 spin_unlock_bh(&dev->device_lock);