source "drivers/staging/p9auth/Kconfig"
-source "drivers/staging/heci/Kconfig"
-
source "drivers/staging/line6/Kconfig"
source "drivers/gpu/drm/radeon/Kconfig"
obj-$(CONFIG_B3DFG) += b3dfg/
obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_PLAN9AUTH) += p9auth/
-obj-$(CONFIG_HECI) += heci/
obj-$(CONFIG_LINE6_USB) += line6/
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/
+++ /dev/null
-config HECI
- tristate "Intel Management Engine Interface (MEI) Support"
- depends on PCI
- ---help---
- The Intel Management Engine Interface (Intel MEI) driver allows
- applications to access the Active Management Technology
- firmware and other Management Engine sub-systems.
+++ /dev/null
-obj-$(CONFIG_HECI) += heci.o
-
-heci-objs := \
- heci_init.o \
- interrupt.o \
- heci_interface.o \
- io_heci.o \
- heci_main.o
-
+++ /dev/null
-TODO:
- - fix user/kernel pointer mess in the ioctl handlers as pointed
- out by sparse.
- - resolve the ioctls and see if most of them can just be simple
- sysfs files
- - fix locking issues that sparse points out at the least.
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-#ifndef _HECI_H_
-#define _HECI_H_
-
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <linux/aio.h>
-#include <linux/types.h>
-#include "heci_data_structures.h"
-
-extern const struct guid heci_pthi_guid;
-extern const struct guid heci_wd_guid;
-extern const __u8 heci_start_wd_params[];
-extern const __u8 heci_stop_wd_params[];
-extern const __u8 heci_wd_state_independence_msg[3][4];
-
-/*
- * heci device ID
- */
-#define HECI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */
-#define HECI_DEV_ID_82G35 0x2984 /* 82G35 Express */
-#define HECI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */
-#define HECI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */
-
-#define HECI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */
-#define HECI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */
-
-#define HECI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */
-#define HECI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */
-#define HECI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */
-#define HECI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */
-#define HECI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */
-
-#define HECI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */
-#define HECI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */
-#define HECI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */
-#define HECI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */
-#define HECI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */
-
-#define HECI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */
-#define HECI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */
-#define HECI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */
-#define HECI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */
-
-#define HECI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */
-#define HECI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */
-#define HECI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */
-#define HECI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */
-
-/*
- * heci init function prototypes
- */
-struct iamt_heci_device *init_heci_device(struct pci_dev *pdev);
-void heci_reset(struct iamt_heci_device *dev, int interrupts);
-int heci_hw_init(struct iamt_heci_device *dev);
-int heci_task_initialize_clients(void *data);
-int heci_initialize_clients(struct iamt_heci_device *dev);
-struct heci_file_private *heci_alloc_file_private(struct file *file);
-int heci_disconnect_host_client(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-void heci_initialize_list(struct io_heci_list *list,
- struct iamt_heci_device *dev);
-void heci_flush_list(struct io_heci_list *list,
- struct heci_file_private *file_ext);
-void heci_flush_queues(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-
-void heci_remove_client_from_file_list(struct iamt_heci_device *dev,
- __u8 host_client_id);
-
-/*
- * interrupt function prototype
- */
-irqreturn_t heci_isr_interrupt(int irq, void *dev_id);
-
-void heci_wd_timer(unsigned long data);
-
-/*
- * input output function prototype
- */
-int heci_ioctl_get_version(struct iamt_heci_device *dev, int if_num,
- struct heci_message_data __user *u_msg,
- struct heci_message_data k_msg,
- struct heci_file_private *file_ext);
-
-int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num,
- struct heci_message_data __user *u_msg,
- struct heci_message_data k_msg,
- struct file *file);
-
-int heci_ioctl_wd(struct iamt_heci_device *dev, int if_num,
- struct heci_message_data k_msg,
- struct heci_file_private *file_ext);
-
-int heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num,
- struct heci_message_data k_msg,
- struct heci_file_private *file_ext);
-
-int heci_start_read(struct iamt_heci_device *dev, int if_num,
- struct heci_file_private *file_ext);
-
-int pthi_write(struct iamt_heci_device *dev,
- struct heci_cb_private *priv_cb);
-
-int pthi_read(struct iamt_heci_device *dev, int if_num, struct file *file,
- char __user *ubuf, size_t length, loff_t *offset);
-
-struct heci_cb_private *find_pthi_read_list_entry(
- struct iamt_heci_device *dev,
- struct file *file);
-
-void run_next_iamthif_cmd(struct iamt_heci_device *dev);
-
-void heci_free_cb_private(struct heci_cb_private *priv_cb);
-
-/**
- * heci_fe_same_id - tell if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns !=0 - if ids are the same, 0 - if differ.
- */
-static inline int heci_fe_same_id(const struct heci_file_private *fe1,
- const struct heci_file_private *fe2)
-{
- return ((fe1->host_client_id == fe2->host_client_id)
- && (fe1->me_client_id == fe2->me_client_id));
-}
-
-#endif /* _HECI_H_ */
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-#ifndef _HECI_DATA_STRUCTURES_H_
-#define _HECI_DATA_STRUCTURES_H_
-
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <linux/aio.h>
-#include <linux/types.h>
-
-/*
- * error code definition
- */
-#define ESLOTS_OVERFLOW 1
-#define ECORRUPTED_MESSAGE_HEADER 1000
-#define ECOMPLETE_MESSAGE 1001
-
-#define HECI_FC_MESSAGE_RESERVED_LENGTH 5
-
-/*
- * Number of queue lists used by this driver
- */
-#define HECI_IO_LISTS_NUMBER 7
-
-/*
- * Maximum transmission unit (MTU) of heci messages
- */
-#define IAMTHIF_MTU 4160
-
-
-/*
- * HECI HW Section
- */
-
-/* HECI registers */
-/* H_CB_WW - Host Circular Buffer (CB) Write Window register */
-#define H_CB_WW 0
-/* H_CSR - Host Control Status register */
-#define H_CSR 4
-/* ME_CB_RW - ME Circular Buffer Read Window register (read only) */
-#define ME_CB_RW 8
-/* ME_CSR_HA - ME Control Status Host Access register (read only) */
-#define ME_CSR_HA 0xC
-
-
-/* register bits of H_CSR (Host Control Status register) */
-/* Host Circular Buffer Depth - maximum number of 32-bit entries in CB */
-#define H_CBD 0xFF000000
-/* Host Circular Buffer Write Pointer */
-#define H_CBWP 0x00FF0000
-/* Host Circular Buffer Read Pointer */
-#define H_CBRP 0x0000FF00
-/* Host Reset */
-#define H_RST 0x00000010
-/* Host Ready */
-#define H_RDY 0x00000008
-/* Host Interrupt Generate */
-#define H_IG 0x00000004
-/* Host Interrupt Status */
-#define H_IS 0x00000002
-/* Host Interrupt Enable */
-#define H_IE 0x00000001
-
-
-/* register bits of ME_CSR_HA (ME Control Status Host Access register) */
-/* ME CB (Circular Buffer) Depth HRA (Host Read Access)
- * - host read only access to ME_CBD */
-#define ME_CBD_HRA 0xFF000000
-/* ME CB Write Pointer HRA - host read only access to ME_CBWP */
-#define ME_CBWP_HRA 0x00FF0000
-/* ME CB Read Pointer HRA - host read only access to ME_CBRP */
-#define ME_CBRP_HRA 0x0000FF00
-/* ME Reset HRA - host read only access to ME_RST */
-#define ME_RST_HRA 0x00000010
-/* ME Ready HRA - host read only access to ME_RDY */
-#define ME_RDY_HRA 0x00000008
-/* ME Interrupt Generate HRA - host read only access to ME_IG */
-#define ME_IG_HRA 0x00000004
-/* ME Interrupt Status HRA - host read only access to ME_IS */
-#define ME_IS_HRA 0x00000002
-/* ME Interrupt Enable HRA - host read only access to ME_IE */
-#define ME_IE_HRA 0x00000001
-
-#define HECI_MINORS_BASE 1
-#define HECI_MINORS_COUNT 1
-
-#define HECI_MINOR_NUMBER 1
-#define HECI_MAX_OPEN_HANDLE_COUNT 253
-
-/*
- * debug kernel print macro define
- */
-extern int heci_debug;
-
-#define DBG(format, arg...) do { \
- if (heci_debug) \
- printk(KERN_INFO "heci: %s: " format, __func__, ## arg); \
-} while (0)
-
-
-/*
- * time to wait HECI become ready after init
- */
-#define HECI_INTEROP_TIMEOUT (HZ * 7)
-
-/*
- * watch dog definition
- */
-#define HECI_WATCHDOG_DATA_SIZE 16
-#define HECI_START_WD_DATA_SIZE 20
-#define HECI_WD_PARAMS_SIZE 4
-#define HECI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
-
-#define HECI_WD_HOST_CLIENT_ID 1
-#define HECI_IAMTHIF_HOST_CLIENT_ID 2
-
-struct guid {
- __u32 data1;
- __u16 data2;
- __u16 data3;
- __u8 data4[8];
-};
-
-/* File state */
-enum file_state {
- HECI_FILE_INITIALIZING = 0,
- HECI_FILE_CONNECTING,
- HECI_FILE_CONNECTED,
- HECI_FILE_DISCONNECTING,
- HECI_FILE_DISCONNECTED
-};
-
-/* HECI device states */
-enum heci_states {
- HECI_INITIALIZING = 0,
- HECI_ENABLED,
- HECI_RESETING,
- HECI_DISABLED,
- HECI_RECOVERING_FROM_RESET,
- HECI_POWER_DOWN,
- HECI_POWER_UP
-};
-
-enum iamthif_states {
- HECI_IAMTHIF_IDLE,
- HECI_IAMTHIF_WRITING,
- HECI_IAMTHIF_FLOW_CONTROL,
- HECI_IAMTHIF_READING,
- HECI_IAMTHIF_READ_COMPLETE
-};
-
-enum heci_file_transaction_states {
- HECI_IDLE,
- HECI_WRITING,
- HECI_WRITE_COMPLETE,
- HECI_FLOW_CONTROL,
- HECI_READING,
- HECI_READ_COMPLETE
-};
-
-/* HECI CB */
-enum heci_cb_major_types {
- HECI_READ = 0,
- HECI_WRITE,
- HECI_IOCTL,
- HECI_OPEN,
- HECI_CLOSE
-};
-
-/* HECI user data struct */
-struct heci_message_data {
- __u32 size;
- char *data;
-} __attribute__((packed));
-
-#define HECI_CONNECT_TIMEOUT 3 /* at least 2 seconds */
-
-#define IAMTHIF_STALL_TIMER 12 /* seconds */
-#define IAMTHIF_READ_TIMER 15 /* seconds */
-
-struct heci_cb_private {
- struct list_head cb_list;
- enum heci_cb_major_types major_file_operations;
- void *file_private;
- struct heci_message_data request_buffer;
- struct heci_message_data response_buffer;
- unsigned long information;
- unsigned long read_time;
- struct file *file_object;
-};
-
-/* Private file struct */
-struct heci_file_private {
- struct list_head link;
- struct file *file;
- enum file_state state;
- wait_queue_head_t tx_wait;
- wait_queue_head_t rx_wait;
- wait_queue_head_t wait;
- spinlock_t file_lock; /* file lock */
- spinlock_t read_io_lock; /* read lock */
- spinlock_t write_io_lock; /* write lock */
- int read_pending;
- int status;
- /* ID of client connected */
- __u8 host_client_id;
- __u8 me_client_id;
- __u8 flow_ctrl_creds;
- __u8 timer_count;
- enum heci_file_transaction_states reading_state;
- enum heci_file_transaction_states writing_state;
- int sm_state;
- struct heci_cb_private *read_cb;
-};
-
-struct io_heci_list {
- struct heci_cb_private heci_cb;
- int status;
- struct iamt_heci_device *device_extension;
-};
-
-struct heci_driver_version {
- __u8 major;
- __u8 minor;
- __u8 hotfix;
- __u16 build;
-} __attribute__((packed));
-
-
-struct heci_client {
- __u32 max_msg_length;
- __u8 protocol_version;
-} __attribute__((packed));
-
-/*
- * HECI BUS Interface Section
- */
-struct heci_msg_hdr {
- __u32 me_addr:8;
- __u32 host_addr:8;
- __u32 length:9;
- __u32 reserved:6;
- __u32 msg_complete:1;
-} __attribute__((packed));
-
-
-struct hbm_cmd {
- __u8 cmd:7;
- __u8 is_response:1;
-} __attribute__((packed));
-
-
-struct heci_bus_message {
- struct hbm_cmd cmd;
- __u8 command_specific_data[];
-} __attribute__((packed));
-
-struct hbm_version {
- __u8 minor_version;
- __u8 major_version;
-} __attribute__((packed));
-
-struct hbm_host_version_request {
- struct hbm_cmd cmd;
- __u8 reserved;
- struct hbm_version host_version;
-} __attribute__((packed));
-
-struct hbm_host_version_response {
- struct hbm_cmd cmd;
- int host_version_supported;
- struct hbm_version me_max_version;
-} __attribute__((packed));
-
-struct hbm_host_stop_request {
- struct hbm_cmd cmd;
- __u8 reason;
- __u8 reserved[2];
-} __attribute__((packed));
-
-struct hbm_host_stop_response {
- struct hbm_cmd cmd;
- __u8 reserved[3];
-} __attribute__((packed));
-
-struct hbm_me_stop_request {
- struct hbm_cmd cmd;
- __u8 reason;
- __u8 reserved[2];
-} __attribute__((packed));
-
-struct hbm_host_enum_request {
- struct hbm_cmd cmd;
- __u8 reserved[3];
-} __attribute__((packed));
-
-struct hbm_host_enum_response {
- struct hbm_cmd cmd;
- __u8 reserved[3];
- __u8 valid_addresses[32];
-} __attribute__((packed));
-
-struct heci_client_properties {
- struct guid protocol_name;
- __u8 protocol_version;
- __u8 max_number_of_connections;
- __u8 fixed_address;
- __u8 single_recv_buf;
- __u32 max_msg_length;
-} __attribute__((packed));
-
-struct hbm_props_request {
- struct hbm_cmd cmd;
- __u8 address;
- __u8 reserved[2];
-} __attribute__((packed));
-
-
-struct hbm_props_response {
- struct hbm_cmd cmd;
- __u8 address;
- __u8 status;
- __u8 reserved[1];
- struct heci_client_properties client_properties;
-} __attribute__((packed));
-
-struct hbm_client_connect_request {
- struct hbm_cmd cmd;
- __u8 me_addr;
- __u8 host_addr;
- __u8 reserved;
-} __attribute__((packed));
-
-struct hbm_client_connect_response {
- struct hbm_cmd cmd;
- __u8 me_addr;
- __u8 host_addr;
- __u8 status;
-} __attribute__((packed));
-
-struct hbm_client_disconnect_request {
- struct hbm_cmd cmd;
- __u8 me_addr;
- __u8 host_addr;
- __u8 reserved[1];
-} __attribute__((packed));
-
-struct hbm_flow_control {
- struct hbm_cmd cmd;
- __u8 me_addr;
- __u8 host_addr;
- __u8 reserved[HECI_FC_MESSAGE_RESERVED_LENGTH];
-} __attribute__((packed));
-
-struct heci_me_client {
- struct heci_client_properties props;
- __u8 client_id;
- __u8 flow_ctrl_creds;
-} __attribute__((packed));
-
-/* private device struct */
-struct iamt_heci_device {
- struct pci_dev *pdev; /* pointer to pci device struct */
- /*
- * lists of queues
- */
- /* array of pointers to aio lists */
- struct io_heci_list *io_list_array[HECI_IO_LISTS_NUMBER];
- struct io_heci_list read_list; /* driver read queue */
- struct io_heci_list write_list; /* driver write queue */
- struct io_heci_list write_waiting_list; /* write waiting queue */
- struct io_heci_list ctrl_wr_list; /* managed write IOCTL list */
- struct io_heci_list ctrl_rd_list; /* managed read IOCTL list */
- struct io_heci_list pthi_cmd_list; /* PTHI list for cmd waiting */
-
- /* driver managed PTHI list for reading completed pthi cmd data */
- struct io_heci_list pthi_read_complete_list;
- /*
- * list of files
- */
- struct list_head file_list;
- /*
- * memory of device
- */
- unsigned int mem_base;
- unsigned int mem_length;
- void __iomem *mem_addr;
- /*
- * lock for the device
- */
- spinlock_t device_lock; /* device lock*/
- struct work_struct work;
- int recvd_msg;
-
- struct task_struct *reinit_tsk;
-
- struct timer_list wd_timer;
- /*
- * hw states of host and fw(ME)
- */
- __u32 host_hw_state;
- __u32 me_hw_state;
- /*
- * waiting queue for receive message from FW
- */
- wait_queue_head_t wait_recvd_msg;
- wait_queue_head_t wait_stop_wd;
- /*
- * heci device states
- */
- enum heci_states heci_state;
- int stop;
-
- __u32 extra_write_index;
- __u32 rd_msg_buf[128]; /* used for control messages */
- __u32 wr_msg_buf[128]; /* used for control messages */
- __u32 ext_msg_buf[8]; /* for control responses */
- __u32 rd_msg_hdr;
-
- struct hbm_version version;
-
- int host_buffer_is_empty;
- struct heci_file_private wd_file_ext;
- struct heci_me_client *me_clients; /* Note: memory has to be allocated*/
- __u8 heci_me_clients[32]; /* list of existing clients */
- __u8 num_heci_me_clients;
- __u8 heci_host_clients[32]; /* list of existing clients */
- __u8 current_host_client_id;
-
- int wd_pending;
- int wd_stoped;
- __u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
- unsigned char wd_data[HECI_START_WD_DATA_SIZE];
-
-
- __u16 wd_due_counter;
- int asf_mode;
- int wd_bypass; /* if 1, don't refresh watchdog ME client */
-
- struct file *iamthif_file_object;
- struct heci_file_private iamthif_file_ext;
- int iamthif_ioctl;
- int iamthif_canceled;
- __u32 iamthif_timer;
- __u32 iamthif_stall_timer;
- unsigned char iamthif_msg_buf[IAMTHIF_MTU];
- __u32 iamthif_msg_buf_size;
- __u32 iamthif_msg_buf_index;
- int iamthif_flow_control_pending;
- enum iamthif_states iamthif_state;
-
- struct heci_cb_private *iamthif_current_cb;
- __u8 write_hang;
- int need_reset;
- long open_handle_count;
-
-};
-
-/**
- * read_heci_register - Read a byte from the heci device
- *
- * @dev: the device structure
- * @offset: offset from which to read the data
- *
- * returns the byte read.
- */
-static inline __u32 read_heci_register(struct iamt_heci_device *dev,
- unsigned long offset)
-{
- return readl(dev->mem_addr + offset);
-}
-
-/**
- * write_heci_register - Write 4 bytes to the heci device
- *
- * @dev: the device structure
- * @offset: offset from which to write the data
- * @value: the byte to write
- */
-static inline void write_heci_register(struct iamt_heci_device *dev,
- unsigned long offset, __u32 value)
-{
- writel(value, dev->mem_addr + offset);
-}
-
-#endif /* _HECI_DATA_STRUCTURES_H_ */
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/reboot.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/moduleparam.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-
-#include "heci_data_structures.h"
-#include "heci_interface.h"
-#include "heci.h"
-
-
-const __u8 heci_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
-const __u8 heci_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
-
-const __u8 heci_wd_state_independence_msg[3][4] = {
- {0x05, 0x02, 0x51, 0x10},
- {0x05, 0x02, 0x52, 0x10},
- {0x07, 0x02, 0x01, 0x10}
-};
-
-static const struct guid heci_asf_guid = {
- 0x75B30CD6, 0xA29E, 0x4AF7,
- {0xA7, 0x12, 0xE6, 0x17, 0x43, 0x93, 0xC8, 0xA6}
-};
-const struct guid heci_wd_guid = {
- 0x05B79A6F, 0x4628, 0x4D7F,
- {0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB}
-};
-const struct guid heci_pthi_guid = {
- 0x12f80028, 0xb4b7, 0x4b2d,
- {0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c}
-};
-
-
-/*
- * heci init function prototypes
- */
-static void heci_check_asf_mode(struct iamt_heci_device *dev);
-static int host_start_message(struct iamt_heci_device *dev);
-static int host_enum_clients_message(struct iamt_heci_device *dev);
-static int allocate_me_clients_storage(struct iamt_heci_device *dev);
-static void host_init_wd(struct iamt_heci_device *dev);
-static void host_init_iamthif(struct iamt_heci_device *dev);
-static int heci_wait_event_int_timeout(struct iamt_heci_device *dev,
- long timeout);
-
-
-/**
- * heci_initialize_list - Sets up a queue list.
- *
- * @list: An instance of our list structure
- * @dev: Device object for our driver
- */
-void heci_initialize_list(struct io_heci_list *list,
- struct iamt_heci_device *dev)
-{
- /* initialize our queue list */
- INIT_LIST_HEAD(&list->heci_cb.cb_list);
- list->status = 0;
- list->device_extension = dev;
-}
-
-/**
- * heci_flush_queues - flush our queues list belong to file_ext.
- *
- * @dev: Device object for our driver
- * @file_ext: private data of the file object
- */
-void heci_flush_queues(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- int i;
-
- if (!dev || !file_ext)
- return;
-
- /* flush our queue list belong to file_ext */
- for (i = 0; i < HECI_IO_LISTS_NUMBER; i++) {
- DBG("remove list entry belong to file_ext\n");
- heci_flush_list(dev->io_list_array[i], file_ext);
- }
-}
-
-
-/**
- * heci_flush_list - remove list entry belong to file_ext.
- *
- * @list: An instance of our list structure
- * @file_ext: private data of the file object
- */
-void heci_flush_list(struct io_heci_list *list,
- struct heci_file_private *file_ext)
-{
- struct heci_file_private *file_ext_tmp;
- struct heci_cb_private *priv_cb_pos = NULL;
- struct heci_cb_private *priv_cb_next = NULL;
-
- if (!list || !file_ext)
- return;
-
- if (list->status != 0)
- return;
-
- if (list_empty(&list->heci_cb.cb_list))
- return;
-
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &list->heci_cb.cb_list, cb_list) {
- if (priv_cb_pos) {
- file_ext_tmp = (struct heci_file_private *)
- priv_cb_pos->file_private;
- if (file_ext_tmp) {
- if (heci_fe_same_id(file_ext, file_ext_tmp))
- list_del(&priv_cb_pos->cb_list);
- }
- }
- }
-}
-
-/**
- * heci_reset_iamthif_params - initializes heci device iamthif
- *
- * @dev: The heci device structure
- */
-static void heci_reset_iamthif_params(struct iamt_heci_device *dev)
-{
- /* reset iamthif parameters. */
- dev->iamthif_current_cb = NULL;
- dev->iamthif_msg_buf_size = 0;
- dev->iamthif_msg_buf_index = 0;
- dev->iamthif_canceled = 0;
- dev->iamthif_file_ext.file = NULL;
- dev->iamthif_ioctl = 0;
- dev->iamthif_state = HECI_IAMTHIF_IDLE;
- dev->iamthif_timer = 0;
-}
-
-/**
- * init_heci_device - allocates and initializes the heci device structure
- *
- * @pdev: The pci device structure
- *
- * returns The heci_device_device pointer on success, NULL on failure.
- */
-struct iamt_heci_device *init_heci_device(struct pci_dev *pdev)
-{
- int i;
- struct iamt_heci_device *dev;
-
- dev = kzalloc(sizeof(struct iamt_heci_device), GFP_KERNEL);
- if (!dev)
- return NULL;
-
- /* setup our list array */
- dev->io_list_array[0] = &dev->read_list;
- dev->io_list_array[1] = &dev->write_list;
- dev->io_list_array[2] = &dev->write_waiting_list;
- dev->io_list_array[3] = &dev->ctrl_wr_list;
- dev->io_list_array[4] = &dev->ctrl_rd_list;
- dev->io_list_array[5] = &dev->pthi_cmd_list;
- dev->io_list_array[6] = &dev->pthi_read_complete_list;
- INIT_LIST_HEAD(&dev->file_list);
- INIT_LIST_HEAD(&dev->wd_file_ext.link);
- INIT_LIST_HEAD(&dev->iamthif_file_ext.link);
- spin_lock_init(&dev->device_lock);
- init_waitqueue_head(&dev->wait_recvd_msg);
- init_waitqueue_head(&dev->wait_stop_wd);
- dev->heci_state = HECI_INITIALIZING;
- dev->iamthif_state = HECI_IAMTHIF_IDLE;
-
- /* init work for schedule work */
- INIT_WORK(&dev->work, NULL);
- for (i = 0; i < HECI_IO_LISTS_NUMBER; i++)
- heci_initialize_list(dev->io_list_array[i], dev);
- dev->pdev = pdev;
- return dev;
-}
-
-
-
-
-static int heci_wait_event_int_timeout(struct iamt_heci_device *dev,
- long timeout)
-{
- return wait_event_interruptible_timeout(dev->wait_recvd_msg,
- (dev->recvd_msg), timeout);
-}
-
-/**
- * heci_hw_init - init host and fw to start work.
- *
- * @dev: Device object for our driver
- *
- * returns 0 on success, <0 on failure.
- */
-int heci_hw_init(struct iamt_heci_device *dev)
-{
- int err = 0;
-
- dev->host_hw_state = read_heci_register(dev, H_CSR);
- dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
- DBG("host_hw_state = 0x%08x, mestate = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
-
- if ((dev->host_hw_state & H_IS) == H_IS) {
- /* acknowledge interrupt and stop interupts */
- heci_csr_clear_his(dev);
- }
- dev->recvd_msg = 0;
- DBG("reset in start the heci device.\n");
-
- heci_reset(dev, 1);
-
- DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
-
- /* wait for ME to turn on ME_RDY */
- if (!dev->recvd_msg)
- err = heci_wait_event_int_timeout(dev, HECI_INTEROP_TIMEOUT);
-
- if (!err && !dev->recvd_msg) {
- dev->heci_state = HECI_DISABLED;
- DBG("wait_event_interruptible_timeout failed"
- "on wait for ME to turn on ME_RDY.\n");
- return -ENODEV;
- } else {
- if (!(((dev->host_hw_state & H_RDY) == H_RDY)
- && ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
- dev->heci_state = HECI_DISABLED;
- DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
- dev->host_hw_state,
- dev->me_hw_state);
-
- if (!(dev->host_hw_state & H_RDY) != H_RDY)
- DBG("host turn off H_RDY.\n");
-
- if (!(dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
- DBG("ME turn off ME_RDY.\n");
-
- printk(KERN_ERR
- "heci: link layer initialization failed.\n");
- return -ENODEV;
- }
- }
- dev->recvd_msg = 0;
- DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
- DBG("ME turn on ME_RDY and host turn on H_RDY.\n");
- printk(KERN_INFO "heci: link layer has been established.\n");
- return 0;
-}
-
-/**
- * heci_hw_reset - reset fw via heci csr register.
- *
- * @dev: Device object for our driver
- * @interrupts: if interrupt should be enable after reset.
- */
-static void heci_hw_reset(struct iamt_heci_device *dev, int interrupts)
-{
- dev->host_hw_state |= (H_RST | H_IG);
-
- if (interrupts)
- heci_csr_enable_interrupts(dev);
- else
- heci_csr_disable_interrupts(dev);
-
- BUG_ON((dev->host_hw_state & H_RST) != H_RST);
- BUG_ON((dev->host_hw_state & H_RDY) != 0);
-}
-
-/**
- * heci_reset - reset host and fw.
- *
- * @dev: Device object for our driver
- * @interrupts: if interrupt should be enable after reset.
- */
-void heci_reset(struct iamt_heci_device *dev, int interrupts)
-{
- struct heci_file_private *file_pos = NULL;
- struct heci_file_private *file_next = NULL;
- struct heci_cb_private *priv_cb_pos = NULL;
- struct heci_cb_private *priv_cb_next = NULL;
- int unexpected = 0;
-
- if (dev->heci_state == HECI_RECOVERING_FROM_RESET) {
- dev->need_reset = 1;
- return;
- }
-
- if (dev->heci_state != HECI_INITIALIZING &&
- dev->heci_state != HECI_DISABLED &&
- dev->heci_state != HECI_POWER_DOWN &&
- dev->heci_state != HECI_POWER_UP)
- unexpected = 1;
-
- if (dev->reinit_tsk != NULL) {
- kthread_stop(dev->reinit_tsk);
- dev->reinit_tsk = NULL;
- }
-
- dev->host_hw_state = read_heci_register(dev, H_CSR);
-
- DBG("before reset host_hw_state = 0x%08x.\n",
- dev->host_hw_state);
-
- heci_hw_reset(dev, interrupts);
-
- dev->host_hw_state &= ~H_RST;
- dev->host_hw_state |= H_IG;
-
- heci_set_csr_register(dev);
-
- DBG("currently saved host_hw_state = 0x%08x.\n",
- dev->host_hw_state);
-
- dev->need_reset = 0;
-
- if (dev->heci_state != HECI_INITIALIZING) {
- if ((dev->heci_state != HECI_DISABLED) &&
- (dev->heci_state != HECI_POWER_DOWN))
- dev->heci_state = HECI_RESETING;
-
- list_for_each_entry_safe(file_pos,
- file_next, &dev->file_list, link) {
- file_pos->state = HECI_FILE_DISCONNECTED;
- file_pos->flow_ctrl_creds = 0;
- file_pos->read_cb = NULL;
- file_pos->timer_count = 0;
- }
- /* remove entry if already in list */
- DBG("list del iamthif and wd file list.\n");
- heci_remove_client_from_file_list(dev,
- dev->wd_file_ext.host_client_id);
-
- heci_remove_client_from_file_list(dev,
- dev->iamthif_file_ext.host_client_id);
-
- heci_reset_iamthif_params(dev);
- dev->wd_due_counter = 0;
- dev->extra_write_index = 0;
- }
-
- dev->num_heci_me_clients = 0;
- dev->rd_msg_hdr = 0;
- dev->stop = 0;
- dev->wd_pending = 0;
-
- /* update the state of the registers after reset */
- dev->host_hw_state = read_heci_register(dev, H_CSR);
- dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
-
- DBG("after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
-
- if (unexpected)
- printk(KERN_WARNING "heci: unexpected reset.\n");
-
- /* Wake up all readings so they can be interrupted */
- list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) {
- if (&file_pos->rx_wait &&
- waitqueue_active(&file_pos->rx_wait)) {
- printk(KERN_INFO "heci: Waking up client!\n");
- wake_up_interruptible(&file_pos->rx_wait);
- }
- }
- /* remove all waiting requests */
- if (dev->write_list.status == 0 &&
- !list_empty(&dev->write_list.heci_cb.cb_list)) {
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &dev->write_list.heci_cb.cb_list, cb_list) {
- if (priv_cb_pos) {
- list_del(&priv_cb_pos->cb_list);
- heci_free_cb_private(priv_cb_pos);
- }
- }
- }
-}
-
-/**
- * heci_initialize_clients - heci communication initialization.
- *
- * @dev: Device object for our driver
- */
-int heci_initialize_clients(struct iamt_heci_device *dev)
-{
- int status;
-
- msleep(100); /* FW needs time to be ready to talk with us */
- DBG("link is established start sending messages.\n");
- /* link is established start sending messages. */
- status = host_start_message(dev);
- if (status != 0) {
- spin_lock_bh(&dev->device_lock);
- dev->heci_state = HECI_DISABLED;
- spin_unlock_bh(&dev->device_lock);
- DBG("start sending messages failed.\n");
- return status;
- }
-
- /* enumerate clients */
- status = host_enum_clients_message(dev);
- if (status != 0) {
- spin_lock_bh(&dev->device_lock);
- dev->heci_state = HECI_DISABLED;
- spin_unlock_bh(&dev->device_lock);
- DBG("enum clients failed.\n");
- return status;
- }
- /* allocate storage for ME clients representation */
- status = allocate_me_clients_storage(dev);
- if (status != 0) {
- spin_lock_bh(&dev->device_lock);
- dev->num_heci_me_clients = 0;
- dev->heci_state = HECI_DISABLED;
- spin_unlock_bh(&dev->device_lock);
- DBG("allocate clients failed.\n");
- return status;
- }
-
- heci_check_asf_mode(dev);
- /*heci initialization wd */
- host_init_wd(dev);
- /*heci initialization iamthif client */
- host_init_iamthif(dev);
-
- spin_lock_bh(&dev->device_lock);
- if (dev->need_reset) {
- dev->need_reset = 0;
- dev->heci_state = HECI_DISABLED;
- spin_unlock_bh(&dev->device_lock);
- return -ENODEV;
- }
-
- memset(dev->heci_host_clients, 0, sizeof(dev->heci_host_clients));
- dev->open_handle_count = 0;
- dev->heci_host_clients[0] |= 7;
- dev->current_host_client_id = 3;
- dev->heci_state = HECI_ENABLED;
- spin_unlock_bh(&dev->device_lock);
- DBG("initialization heci clients successful.\n");
- return 0;
-}
-
-/**
- * heci_task_initialize_clients - heci reinitialization task
- *
- * @data: Device object for our driver
- */
-int heci_task_initialize_clients(void *data)
-{
- int ret;
- struct iamt_heci_device *dev = (struct iamt_heci_device *) data;
-
- spin_lock_bh(&dev->device_lock);
- if (dev->reinit_tsk != NULL) {
- spin_unlock_bh(&dev->device_lock);
- DBG("reinit task already started.\n");
- return 0;
- }
- dev->reinit_tsk = current;
- current->flags |= PF_NOFREEZE;
- spin_unlock_bh(&dev->device_lock);
-
- ret = heci_initialize_clients(dev);
-
- spin_lock_bh(&dev->device_lock);
- dev->reinit_tsk = NULL;
- spin_unlock_bh(&dev->device_lock);
-
- return ret;
-}
-
-/**
- * host_start_message - heci host send start message.
- *
- * @dev: Device object for our driver
- *
- * returns 0 on success, <0 on failure.
- */
-static int host_start_message(struct iamt_heci_device *dev)
-{
- long timeout = 60; /* 60 second */
-
- struct heci_msg_hdr *heci_hdr;
- struct hbm_host_version_request *host_start_req;
- struct hbm_host_stop_request *host_stop_req;
- int err = 0;
-
- /* host start message */
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length = sizeof(struct hbm_host_version_request);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- host_start_req =
- (struct hbm_host_version_request *) &dev->wr_msg_buf[1];
- memset(host_start_req, 0, sizeof(struct hbm_host_version_request));
- host_start_req->cmd.cmd = HOST_START_REQ_CMD;
- host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
- host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
- dev->recvd_msg = 0;
- if (!heci_write_message(dev, heci_hdr,
- (unsigned char *) (host_start_req),
- heci_hdr->length)) {
- DBG("send version to fw fail.\n");
- return -ENODEV;
- }
- DBG("call wait_event_interruptible_timeout for response message.\n");
- /* wait for response */
- err = heci_wait_event_int_timeout(dev, timeout * HZ);
- if (!err && !dev->recvd_msg) {
- DBG("wait_timeout failed on host start response message.\n");
- return -ENODEV;
- }
- dev->recvd_msg = 0;
- DBG("wait_timeout successful on host start response message.\n");
- if ((dev->version.major_version != HBM_MAJOR_VERSION) ||
- (dev->version.minor_version != HBM_MINOR_VERSION)) {
- /* send stop message */
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length = sizeof(struct hbm_host_stop_request);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- host_stop_req =
- (struct hbm_host_stop_request *) &dev->wr_msg_buf[1];
-
- memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
- host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
- host_stop_req->reason = DRIVER_STOP_REQUEST;
- heci_write_message(dev, heci_hdr,
- (unsigned char *) (host_stop_req),
- heci_hdr->length);
- DBG("version mismatch.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-/**
- * host_enum_clients_message - host send enumeration client request message.
- *
- * @dev: Device object for our driver
- *
- * returns 0 on success, <0 on failure.
- */
-static int host_enum_clients_message(struct iamt_heci_device *dev)
-{
- long timeout = 5; /*5 second */
- struct heci_msg_hdr *heci_hdr;
- struct hbm_host_enum_request *host_enum_req;
- int err = 0;
- int i, j;
-
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- /* enumerate clients */
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length = sizeof(struct hbm_host_enum_request);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
- memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request));
- host_enum_req->cmd.cmd = HOST_ENUM_REQ_CMD;
- if (!heci_write_message(dev, heci_hdr,
- (unsigned char *) (host_enum_req),
- heci_hdr->length)) {
- DBG("send enumeration request failed.\n");
- return -ENODEV;
- }
- /* wait for response */
- dev->recvd_msg = 0;
- err = heci_wait_event_int_timeout(dev, timeout * HZ);
- if (!err && !dev->recvd_msg) {
- DBG("wait_event_interruptible_timeout failed "
- "on enumeration clients response message.\n");
- return -ENODEV;
- }
- dev->recvd_msg = 0;
-
- spin_lock_bh(&dev->device_lock);
- /* count how many ME clients we have */
- for (i = 0; i < sizeof(dev->heci_me_clients); i++) {
- for (j = 0; j < 8; j++) {
- if ((dev->heci_me_clients[i] & (1 << j)) != 0)
- dev->num_heci_me_clients++;
-
- }
- }
- spin_unlock_bh(&dev->device_lock);
-
- return 0;
-}
-
-/**
- * host_client_properties - reads properties for client
- *
- * @dev: Device object for our driver
- * @idx: client index in me client array
- * @client_id: id of the client
- *
- * returns 0 on success, <0 on failure.
- */
-static int host_client_properties(struct iamt_heci_device *dev,
- struct heci_me_client *client)
-{
- struct heci_msg_hdr *heci_hdr;
- struct hbm_props_request *host_cli_req;
- int err;
-
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length = sizeof(struct hbm_props_request);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- host_cli_req = (struct hbm_props_request *) &dev->wr_msg_buf[1];
- memset(host_cli_req, 0, sizeof(struct hbm_props_request));
- host_cli_req->cmd.cmd = HOST_CLIENT_PROPERTEIS_REQ_CMD;
- host_cli_req->address = client->client_id;
- if (!heci_write_message(dev, heci_hdr,
- (unsigned char *) (host_cli_req),
- heci_hdr->length)) {
- DBG("send props request failed.\n");
- return -ENODEV;
- }
- /* wait for response */
- dev->recvd_msg = 0;
- err = heci_wait_event_int_timeout(dev, 10 * HZ);
- if (!err && !dev->recvd_msg) {
- DBG("wait failed on props resp msg.\n");
- return -ENODEV;
- }
- dev->recvd_msg = 0;
- return 0;
-}
-
-/**
- * allocate_me_clients_storage - allocate storage for me clients
- *
- * @dev: Device object for our driver
- *
- * returns 0 on success, <0 on failure.
- */
-static int allocate_me_clients_storage(struct iamt_heci_device *dev)
-{
- struct heci_me_client *clients;
- struct heci_me_client *client;
- __u8 num, i, j;
- int err;
-
- if (dev->num_heci_me_clients <= 0)
- return 0;
-
- spin_lock_bh(&dev->device_lock);
- kfree(dev->me_clients);
- dev->me_clients = NULL;
- spin_unlock_bh(&dev->device_lock);
-
- /* allocate storage for ME clients representation */
- clients = kcalloc(dev->num_heci_me_clients,
- sizeof(struct heci_me_client), GFP_KERNEL);
- if (!clients) {
- DBG("memory allocation for ME clients failed.\n");
- return -ENOMEM;
- }
-
- spin_lock_bh(&dev->device_lock);
- dev->me_clients = clients;
- spin_unlock_bh(&dev->device_lock);
-
- num = 0;
- for (i = 0; i < sizeof(dev->heci_me_clients); i++) {
- for (j = 0; j < 8; j++) {
- if ((dev->heci_me_clients[i] & (1 << j)) != 0) {
- client = &dev->me_clients[num];
- client->client_id = (i * 8) + j;
- client->flow_ctrl_creds = 0;
- err = host_client_properties(dev, client);
- if (err != 0) {
- spin_lock_bh(&dev->device_lock);
- kfree(dev->me_clients);
- dev->me_clients = NULL;
- spin_unlock_bh(&dev->device_lock);
- return err;
- }
- num++;
- }
- }
- }
-
- return 0;
-}
-
-/**
- * heci_init_file_private - initializes private file structure.
- *
- * @priv: private file structure to be initialized
- * @file: the file structure
- */
-static void heci_init_file_private(struct heci_file_private *priv,
- struct file *file)
-{
- memset(priv, 0, sizeof(struct heci_file_private));
- spin_lock_init(&priv->file_lock);
- spin_lock_init(&priv->read_io_lock);
- spin_lock_init(&priv->write_io_lock);
- init_waitqueue_head(&priv->wait);
- init_waitqueue_head(&priv->rx_wait);
- DBG("priv->rx_wait =%p\n", &priv->rx_wait);
- init_waitqueue_head(&priv->tx_wait);
- INIT_LIST_HEAD(&priv->link);
- priv->reading_state = HECI_IDLE;
- priv->writing_state = HECI_IDLE;
-}
-
-/**
- * heci_find_me_client - search for ME client guid
- * sets client_id in heci_file_private if found
- * @dev: Device object for our driver
- * @priv: private file structure to set client_id in
- * @cguid: searched guid of ME client
- * @client_id: id of host client to be set in file private structure
- *
- * returns ME client index
- */
-static __u8 heci_find_me_client(struct iamt_heci_device *dev,
- struct heci_file_private *priv,
- const struct guid *cguid, __u8 client_id)
-{
- __u8 i;
-
- if ((dev == NULL) || (priv == NULL) || (cguid == NULL))
- return 0;
-
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (memcmp(cguid,
- &dev->me_clients[i].props.protocol_name,
- sizeof(struct guid)) == 0) {
- priv->me_client_id = dev->me_clients[i].client_id;
- priv->state = HECI_FILE_CONNECTING;
- priv->host_client_id = client_id;
-
- list_add_tail(&priv->link, &dev->file_list);
- return i;
- }
- }
- return 0;
-}
-
-/**
- * heci_check_asf_mode - check for ASF client
- *
- * @dev: Device object for our driver
- */
-static void heci_check_asf_mode(struct iamt_heci_device *dev)
-{
- __u8 i;
-
- spin_lock_bh(&dev->device_lock);
- dev->asf_mode = 0;
- /* find ME ASF client - otherwise assume AMT mode */
- DBG("find ME ASF client - otherwise assume AMT mode.\n");
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (memcmp(&heci_asf_guid,
- &dev->me_clients[i].props.protocol_name,
- sizeof(struct guid)) == 0) {
- dev->asf_mode = 1;
- spin_unlock_bh(&dev->device_lock);
- DBG("found ME ASF client.\n");
- return;
- }
- }
- spin_unlock_bh(&dev->device_lock);
- DBG("assume AMT mode.\n");
-}
-
-/**
- * heci_connect_me_client - connect ME client
- * @dev: Device object for our driver
- * @priv: private file structure
- * @timeout: connect timeout in seconds
- *
- * returns 1 - if connected, 0 - if not
- */
-static __u8 heci_connect_me_client(struct iamt_heci_device *dev,
- struct heci_file_private *priv,
- long timeout)
-{
- int err = 0;
-
- if ((dev == NULL) || (priv == NULL))
- return 0;
-
- if (!heci_connect(dev, priv)) {
- DBG("failed to call heci_connect for client_id=%d.\n",
- priv->host_client_id);
- spin_lock_bh(&dev->device_lock);
- heci_remove_client_from_file_list(dev, priv->host_client_id);
- priv->state = HECI_FILE_DISCONNECTED;
- spin_unlock_bh(&dev->device_lock);
- return 0;
- }
-
- err = wait_event_timeout(dev->wait_recvd_msg,
- (HECI_FILE_CONNECTED == priv->state ||
- HECI_FILE_DISCONNECTED == priv->state),
- timeout * HZ);
- if (HECI_FILE_CONNECTED != priv->state) {
- spin_lock_bh(&dev->device_lock);
- heci_remove_client_from_file_list(dev, priv->host_client_id);
- DBG("failed to connect client_id=%d state=%d.\n",
- priv->host_client_id, priv->state);
- if (err)
- DBG("failed connect err=%08x\n", err);
- priv->state = HECI_FILE_DISCONNECTED;
- spin_unlock_bh(&dev->device_lock);
- return 0;
- }
- DBG("successfully connected client_id=%d.\n",
- priv->host_client_id);
- return 1;
-}
-
-/**
- * host_init_wd - heci initialization wd.
- *
- * @dev: Device object for our driver
- */
-static void host_init_wd(struct iamt_heci_device *dev)
-{
- spin_lock_bh(&dev->device_lock);
-
- heci_init_file_private(&dev->wd_file_ext, NULL);
-
- /* look for WD client and connect to it */
- dev->wd_file_ext.state = HECI_FILE_DISCONNECTED;
- dev->wd_timeout = 0;
-
- if (dev->asf_mode) {
- memcpy(dev->wd_data, heci_stop_wd_params, HECI_WD_PARAMS_SIZE);
- } else {
- /* AMT mode */
- dev->wd_timeout = AMT_WD_VALUE;
- DBG("dev->wd_timeout=%d.\n", dev->wd_timeout);
- memcpy(dev->wd_data, heci_start_wd_params, HECI_WD_PARAMS_SIZE);
- memcpy(dev->wd_data + HECI_WD_PARAMS_SIZE,
- &dev->wd_timeout, sizeof(__u16));
- }
-
- /* find ME WD client */
- heci_find_me_client(dev, &dev->wd_file_ext,
- &heci_wd_guid, HECI_WD_HOST_CLIENT_ID);
- spin_unlock_bh(&dev->device_lock);
-
- DBG("check wd_file_ext\n");
- if (HECI_FILE_CONNECTING == dev->wd_file_ext.state) {
- if (heci_connect_me_client(dev, &dev->wd_file_ext, 15) == 1) {
- DBG("dev->wd_timeout=%d.\n", dev->wd_timeout);
- if (dev->wd_timeout != 0)
- dev->wd_due_counter = 1;
- else
- dev->wd_due_counter = 0;
- DBG("successfully connected to WD client.\n");
- }
- } else
- DBG("failed to find WD client.\n");
-
-
- spin_lock_bh(&dev->device_lock);
- dev->wd_timer.function = &heci_wd_timer;
- dev->wd_timer.data = (unsigned long) dev;
- spin_unlock_bh(&dev->device_lock);
-}
-
-
-/**
- * host_init_iamthif - heci initialization iamthif client.
- *
- * @dev: Device object for our driver
- *
- */
-static void host_init_iamthif(struct iamt_heci_device *dev)
-{
- __u8 i;
-
- spin_lock_bh(&dev->device_lock);
-
- heci_init_file_private(&dev->iamthif_file_ext, NULL);
- dev->iamthif_file_ext.state = HECI_FILE_DISCONNECTED;
-
- /* find ME PTHI client */
- i = heci_find_me_client(dev, &dev->iamthif_file_ext,
- &heci_pthi_guid, HECI_IAMTHIF_HOST_CLIENT_ID);
- if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTING) {
- DBG("failed to find iamthif client.\n");
- spin_unlock_bh(&dev->device_lock);
- return;
- }
-
- BUG_ON(dev->me_clients[i].props.max_msg_length != IAMTHIF_MTU);
-
- spin_unlock_bh(&dev->device_lock);
- if (heci_connect_me_client(dev, &dev->iamthif_file_ext, 15) == 1) {
- DBG("connected to iamthif client.\n");
- dev->iamthif_state = HECI_IAMTHIF_IDLE;
- }
-}
-
-/**
- * heci_alloc_file_private - allocates a private file structure and set it up.
- * @file: the file structure
- *
- * returns The allocated file or NULL on failure
- */
-struct heci_file_private *heci_alloc_file_private(struct file *file)
-{
- struct heci_file_private *priv;
-
- priv = kmalloc(sizeof(struct heci_file_private), GFP_KERNEL);
- if (!priv)
- return NULL;
-
- heci_init_file_private(priv, file);
-
- return priv;
-}
-
-
-
-/**
- * heci_disconnect_host_client - send disconnect message to fw from host client.
- *
- * @dev: Device object for our driver
- * @file_ext: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int heci_disconnect_host_client(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- int rets, err;
- long timeout = 15; /* 15 seconds */
- struct heci_cb_private *priv_cb;
-
- if ((!dev) || (!file_ext))
- return -ENODEV;
-
- spin_lock_bh(&dev->device_lock);
- if (file_ext->state != HECI_FILE_DISCONNECTING) {
- spin_unlock_bh(&dev->device_lock);
- return 0;
- }
- spin_unlock_bh(&dev->device_lock);
-
- priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
- if (!priv_cb)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&priv_cb->cb_list);
- priv_cb->file_private = file_ext;
- priv_cb->major_file_operations = HECI_CLOSE;
- spin_lock_bh(&dev->device_lock);
- if (dev->host_buffer_is_empty) {
- dev->host_buffer_is_empty = 0;
- if (heci_disconnect(dev, file_ext)) {
- mdelay(10); /* Wait for hardware disconnection ready */
- list_add_tail(&priv_cb->cb_list,
- &dev->ctrl_rd_list.heci_cb.cb_list);
- } else {
- spin_unlock_bh(&dev->device_lock);
- rets = -ENODEV;
- DBG("failed to call heci_disconnect.\n");
- goto free;
- }
- } else {
- DBG("add disconnect cb to control write list\n");
- list_add_tail(&priv_cb->cb_list,
- &dev->ctrl_wr_list.heci_cb.cb_list);
- }
- spin_unlock_bh(&dev->device_lock);
-
- err = wait_event_timeout(dev->wait_recvd_msg,
- (HECI_FILE_DISCONNECTED == file_ext->state),
- timeout * HZ);
-
- spin_lock_bh(&dev->device_lock);
- if (HECI_FILE_DISCONNECTED == file_ext->state) {
- rets = 0;
- DBG("successfully disconnected from fw client.\n");
- } else {
- rets = -ENODEV;
- if (HECI_FILE_DISCONNECTED != file_ext->state)
- DBG("wrong status client disconnect.\n");
-
- if (err)
- DBG("wait failed disconnect err=%08x\n", err);
-
- DBG("failed to disconnect from fw client.\n");
- }
-
- heci_flush_list(&dev->ctrl_rd_list, file_ext);
- heci_flush_list(&dev->ctrl_wr_list, file_ext);
- spin_unlock_bh(&dev->device_lock);
-free:
- heci_free_cb_private(priv_cb);
- return rets;
-}
-
-/**
- * heci_remove_client_from_file_list -
- * remove file private data from device file list
- *
- * @dev: Device object for our driver
- * @host_client_id: host client id to be removed
- */
-void heci_remove_client_from_file_list(struct iamt_heci_device *dev,
- __u8 host_client_id)
-{
- struct heci_file_private *file_pos = NULL;
- struct heci_file_private *file_next = NULL;
- list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) {
- if (host_client_id == file_pos->host_client_id) {
- DBG("remove host client = %d, ME client = %d\n",
- file_pos->host_client_id,
- file_pos->me_client_id);
- list_del_init(&file_pos->link);
- break;
- }
- }
-}
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-
-#include "heci.h"
-#include "heci_interface.h"
-
-
-/**
- * heci_set_csr_register - write H_CSR register to the heci device,
- * and ignore the H_IS bit for it is write-one-to-zero.
- *
- * @dev: device object for our driver
- */
-void heci_set_csr_register(struct iamt_heci_device *dev)
-{
- if ((dev->host_hw_state & H_IS) == H_IS)
- dev->host_hw_state &= ~H_IS;
- write_heci_register(dev, H_CSR, dev->host_hw_state);
- dev->host_hw_state = read_heci_register(dev, H_CSR);
-}
-
-/**
- * heci_csr_enable_interrupts - enable heci device interrupts
- *
- * @dev: device object for our driver
- */
-void heci_csr_enable_interrupts(struct iamt_heci_device *dev)
-{
- dev->host_hw_state |= H_IE;
- heci_set_csr_register(dev);
-}
-
-/**
- * heci_csr_disable_interrupts - disable heci device interrupts
- *
- * @dev: device object for our driver
- */
-void heci_csr_disable_interrupts(struct iamt_heci_device *dev)
-{
- dev->host_hw_state &= ~H_IE;
- heci_set_csr_register(dev);
-}
-
-/**
- * heci_csr_clear_his - clear H_IS bit in H_CSR
- *
- * @dev: device object for our driver
- */
-void heci_csr_clear_his(struct iamt_heci_device *dev)
-{
- write_heci_register(dev, H_CSR, dev->host_hw_state);
- dev->host_hw_state = read_heci_register(dev, H_CSR);
-}
-
-/**
- * _host_get_filled_slots - get number of device filled buffer slots
- *
- * @device: the device structure
- *
- * returns numer of filled slots
- */
-static unsigned char _host_get_filled_slots(const struct iamt_heci_device *dev)
-{
- char read_ptr, write_ptr;
-
- read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
- write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);
-
- return (unsigned char) (write_ptr - read_ptr);
-}
-
-/**
- * host_buffer_is_empty - check if host buffer is empty.
- *
- * @dev: device object for our driver
- *
- * returns 1 if empty, 0 - otherwise.
- */
-int host_buffer_is_empty(struct iamt_heci_device *dev)
-{
- unsigned char filled_slots;
-
- dev->host_hw_state = read_heci_register(dev, H_CSR);
- filled_slots = _host_get_filled_slots(dev);
-
- if (filled_slots > 0)
- return 0;
-
- return 1;
-}
-
-/**
- * count_empty_write_slots - count write empty slots.
- *
- * @dev: device object for our driver
- *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
- */
-__s32 count_empty_write_slots(const struct iamt_heci_device *dev)
-{
- unsigned char buffer_depth, filled_slots, empty_slots;
-
- buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
- filled_slots = _host_get_filled_slots(dev);
- empty_slots = buffer_depth - filled_slots;
-
- if (filled_slots > buffer_depth) {
- /* overflow */
- return -ESLOTS_OVERFLOW;
- }
-
- return (__s32) empty_slots;
-}
-
-/**
- * heci_write_message - write a message to heci device.
- *
- * @dev: device object for our driver
- * @heci_hdr: header of message
- * @write_buffer: message buffer will be write
- * @write_length: message size will be write
- *
- * returns 1 if success, 0 - otherwise.
- */
-int heci_write_message(struct iamt_heci_device *dev,
- struct heci_msg_hdr *header,
- unsigned char *write_buffer,
- unsigned long write_length)
-{
- __u32 temp_msg = 0;
- unsigned long bytes_written = 0;
- unsigned char buffer_depth, filled_slots, empty_slots;
- unsigned long dw_to_write;
-
- dev->host_hw_state = read_heci_register(dev, H_CSR);
- DBG("host_hw_state = 0x%08x.\n", dev->host_hw_state);
- DBG("heci_write_message header=%08x.\n", *((__u32 *) header));
- buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
- filled_slots = _host_get_filled_slots(dev);
- empty_slots = buffer_depth - filled_slots;
- DBG("filled = %hu, empty = %hu.\n", filled_slots, empty_slots);
-
- dw_to_write = ((write_length + 3) / 4);
-
- if (dw_to_write > empty_slots)
- return 0;
-
- write_heci_register(dev, H_CB_WW, *((__u32 *) header));
-
- while (write_length >= 4) {
- write_heci_register(dev, H_CB_WW,
- *(__u32 *) (write_buffer + bytes_written));
- bytes_written += 4;
- write_length -= 4;
- }
-
- if (write_length > 0) {
- memcpy(&temp_msg, &write_buffer[bytes_written], write_length);
- write_heci_register(dev, H_CB_WW, temp_msg);
- }
-
- dev->host_hw_state |= H_IG;
- heci_set_csr_register(dev);
- dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
- if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
- return 0;
-
- dev->write_hang = 0;
- return 1;
-}
-
-/**
- * count_full_read_slots - count read full slots.
- *
- * @dev: device object for our driver
- *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
- */
-__s32 count_full_read_slots(struct iamt_heci_device *dev)
-{
- char read_ptr, write_ptr;
- unsigned char buffer_depth, filled_slots;
-
- dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
- buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24);
- read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8);
- write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16);
- filled_slots = (unsigned char) (write_ptr - read_ptr);
-
- if (filled_slots > buffer_depth) {
- /* overflow */
- return -ESLOTS_OVERFLOW;
- }
-
- DBG("filled_slots =%08x \n", filled_slots);
- return (__s32) filled_slots;
-}
-
-/**
- * heci_read_slots - read a message from heci device.
- *
- * @dev: device object for our driver
- * @buffer: message buffer will be write
- * @buffer_length: message size will be read
- */
-void heci_read_slots(struct iamt_heci_device *dev,
- unsigned char *buffer, unsigned long buffer_length)
-{
- __u32 i = 0;
- unsigned char temp_buf[sizeof(__u32)];
-
- while (buffer_length >= sizeof(__u32)) {
- ((__u32 *) buffer)[i] = read_heci_register(dev, ME_CB_RW);
- DBG("buffer[%d]= %d\n", i, ((__u32 *) buffer)[i]);
- i++;
- buffer_length -= sizeof(__u32);
- }
-
- if (buffer_length > 0) {
- *((__u32 *) &temp_buf) = read_heci_register(dev, ME_CB_RW);
- memcpy(&buffer[i * 4], temp_buf, buffer_length);
- }
-
- dev->host_hw_state |= H_IG;
- heci_set_csr_register(dev);
-}
-
-/**
- * flow_ctrl_creds - check flow_control credentials.
- *
- * @dev: device object for our driver
- * @file_ext: private data of the file object
- *
- * returns 1 if flow_ctrl_creds >0, 0 - otherwise.
- */
-int flow_ctrl_creds(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- __u8 i;
-
- if (!dev->num_heci_me_clients)
- return 0;
-
- if (file_ext == NULL)
- return 0;
-
- if (file_ext->flow_ctrl_creds > 0)
- return 1;
-
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (dev->me_clients[i].client_id == file_ext->me_client_id) {
- if (dev->me_clients[i].flow_ctrl_creds > 0) {
- BUG_ON(dev->me_clients[i].props.single_recv_buf
- == 0);
- return 1;
- }
- return 0;
- }
- }
- BUG();
- return 0;
-}
-
-/**
- * flow_ctrl_reduce - reduce flow_control.
- *
- * @dev: device object for our driver
- * @file_ext: private data of the file object
- */
-void flow_ctrl_reduce(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- __u8 i;
-
- if (!dev->num_heci_me_clients)
- return;
-
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (dev->me_clients[i].client_id == file_ext->me_client_id) {
- if (dev->me_clients[i].props.single_recv_buf != 0) {
- BUG_ON(dev->me_clients[i].flow_ctrl_creds <= 0);
- dev->me_clients[i].flow_ctrl_creds--;
- } else {
- BUG_ON(file_ext->flow_ctrl_creds <= 0);
- file_ext->flow_ctrl_creds--;
- }
- return;
- }
- }
- BUG();
-}
-
-/**
- * heci_send_flow_control - send flow control to fw.
- *
- * @dev: device object for our driver
- * @file_ext: private data of the file object
- *
- * returns 1 if success, 0 - otherwise.
- */
-int heci_send_flow_control(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- struct heci_msg_hdr *heci_hdr;
- struct hbm_flow_control *heci_flow_control;
-
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length = sizeof(struct hbm_flow_control);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- heci_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
- memset(heci_flow_control, 0, sizeof(heci_flow_control));
- heci_flow_control->host_addr = file_ext->host_client_id;
- heci_flow_control->me_addr = file_ext->me_client_id;
- heci_flow_control->cmd.cmd = HECI_FLOW_CONTROL_CMD;
- memset(heci_flow_control->reserved, 0,
- sizeof(heci_flow_control->reserved));
- DBG("sending flow control host client = %d, me client = %d\n",
- file_ext->host_client_id, file_ext->me_client_id);
- if (!heci_write_message(dev, heci_hdr,
- (unsigned char *) heci_flow_control,
- sizeof(struct hbm_flow_control)))
- return 0;
-
- return 1;
-
-}
-
-/**
- * other_client_is_connecting - check if other
- * client with the same client id is connected.
- *
- * @dev: device object for our driver
- * @file_ext: private data of the file object
- *
- * returns 1 if other client is connected, 0 - otherwise.
- */
-int other_client_is_connecting(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- struct heci_file_private *file_pos = NULL;
- struct heci_file_private *file_next = NULL;
-
- list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) {
- if ((file_pos->state == HECI_FILE_CONNECTING)
- && (file_pos != file_ext)
- && file_ext->me_client_id == file_pos->me_client_id)
- return 1;
-
- }
- return 0;
-}
-
-/**
- * heci_send_wd - send watch dog message to fw.
- *
- * @dev: device object for our driver
- *
- * returns 1 if success, 0 - otherwise.
- */
-int heci_send_wd(struct iamt_heci_device *dev)
-{
- struct heci_msg_hdr *heci_hdr;
-
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = dev->wd_file_ext.host_client_id;
- heci_hdr->me_addr = dev->wd_file_ext.me_client_id;
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- if (!memcmp(dev->wd_data, heci_start_wd_params,
- HECI_WD_PARAMS_SIZE)) {
- heci_hdr->length = HECI_START_WD_DATA_SIZE;
- } else {
- BUG_ON(memcmp(dev->wd_data, heci_stop_wd_params,
- HECI_WD_PARAMS_SIZE));
- heci_hdr->length = HECI_WD_PARAMS_SIZE;
- }
-
- if (!heci_write_message(dev, heci_hdr, dev->wd_data, heci_hdr->length))
- return 0;
-
- return 1;
-}
-
-/**
- * heci_disconnect - send disconnect message to fw.
- *
- * @dev: device object for our driver
- * @file_ext: private data of the file object
- *
- * returns 1 if success, 0 - otherwise.
- */
-int heci_disconnect(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- struct heci_msg_hdr *heci_hdr;
- struct hbm_client_disconnect_request *heci_cli_disconnect;
-
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length = sizeof(struct hbm_client_disconnect_request);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- heci_cli_disconnect =
- (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
- memset(heci_cli_disconnect, 0, sizeof(heci_cli_disconnect));
- heci_cli_disconnect->host_addr = file_ext->host_client_id;
- heci_cli_disconnect->me_addr = file_ext->me_client_id;
- heci_cli_disconnect->cmd.cmd = CLIENT_DISCONNECT_REQ_CMD;
- heci_cli_disconnect->reserved[0] = 0;
-
- if (!heci_write_message(dev, heci_hdr,
- (unsigned char *) heci_cli_disconnect,
- sizeof(struct hbm_client_disconnect_request)))
- return 0;
-
- return 1;
-}
-
-/**
- * heci_connect - send connect message to fw.
- *
- * @dev: device object for our driver
- * @file_ext: private data of the file object
- *
- * returns 1 if success, 0 - otherwise.
- */
-int heci_connect(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- struct heci_msg_hdr *heci_hdr;
- struct hbm_client_connect_request *heci_cli_connect;
-
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length = sizeof(struct hbm_client_connect_request);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- heci_cli_connect =
- (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
- heci_cli_connect->host_addr = file_ext->host_client_id;
- heci_cli_connect->me_addr = file_ext->me_client_id;
- heci_cli_connect->cmd.cmd = CLIENT_CONNECT_REQ_CMD;
- heci_cli_connect->reserved = 0;
-
- if (!heci_write_message(dev, heci_hdr,
- (unsigned char *) heci_cli_connect,
- sizeof(struct hbm_client_connect_request)))
- return 0;
-
- return 1;
-}
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-
-#ifndef _HECI_INTERFACE_H_
-#define _HECI_INTERFACE_H_
-
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <linux/aio.h>
-#include <linux/types.h>
-#include "heci_data_structures.h"
-
-
-#define HBM_MINOR_VERSION 0
-#define HBM_MAJOR_VERSION 1
-#define HBM_TIMEOUT 1 /* 1 second */
-
-
-#define HOST_START_REQ_CMD 0x01
-#define HOST_START_RES_CMD 0x81
-
-#define HOST_STOP_REQ_CMD 0x02
-#define HOST_STOP_RES_CMD 0x82
-
-#define ME_STOP_REQ_CMD 0x03
-
-#define HOST_ENUM_REQ_CMD 0x04
-#define HOST_ENUM_RES_CMD 0x84
-
-#define HOST_CLIENT_PROPERTEIS_REQ_CMD 0x05
-#define HOST_CLIENT_PROPERTEIS_RES_CMD 0x85
-
-#define CLIENT_CONNECT_REQ_CMD 0x06
-#define CLIENT_CONNECT_RES_CMD 0x86
-
-#define CLIENT_DISCONNECT_REQ_CMD 0x07
-#define CLIENT_DISCONNECT_RES_CMD 0x87
-
-#define HECI_FLOW_CONTROL_CMD 0x08
-
-
-#define AMT_WD_VALUE 120 /* seconds */
-
-#define HECI_WATCHDOG_DATA_SIZE 16
-#define HECI_START_WD_DATA_SIZE 20
-#define HECI_WD_PARAMS_SIZE 4
-
-/* IOCTL commands */
-#define IOCTL_HECI_GET_VERSION \
- _IOWR('H' , 0x0, struct heci_message_data)
-#define IOCTL_HECI_CONNECT_CLIENT \
- _IOWR('H' , 0x01, struct heci_message_data)
-#define IOCTL_HECI_WD \
- _IOWR('H' , 0x02, struct heci_message_data)
-#define IOCTL_HECI_BYPASS_WD \
- _IOWR('H' , 0x10, struct heci_message_data)
-
-enum heci_stop_reason_types{
- DRIVER_STOP_REQUEST = 0x00,
- DEVICE_D1_ENTRY = 0x01,
- DEVICE_D2_ENTRY = 0x02,
- DEVICE_D3_ENTRY = 0x03,
- SYSTEM_S1_ENTRY = 0x04,
- SYSTEM_S2_ENTRY = 0x05,
- SYSTEM_S3_ENTRY = 0x06,
- SYSTEM_S4_ENTRY = 0x07,
- SYSTEM_S5_ENTRY = 0x08
-};
-
-enum me_stop_reason_types{
- FW_UPDATE = 0x00
-};
-
-enum client_connect_status_types{
- CCS_SUCCESS = 0x00,
- CCS_NOT_FOUND = 0x01,
- CCS_ALREADY_STARTED = 0x02,
- CCS_OUT_OF_RESOURCES = 0x03,
- CCS_MESSAGE_SMALL = 0x04
-};
-
-enum client_disconnect_status_types{
- CDS_SUCCESS = 0x00
-};
-
-
-/*
- * heci interface function prototypes
- */
-void heci_set_csr_register(struct iamt_heci_device *dev);
-void heci_csr_enable_interrupts(struct iamt_heci_device *dev);
-void heci_csr_disable_interrupts(struct iamt_heci_device *dev);
-void heci_csr_clear_his(struct iamt_heci_device *dev);
-
-void heci_read_slots(struct iamt_heci_device *dev,
- unsigned char *buffer, unsigned long buffer_length);
-
-int heci_write_message(struct iamt_heci_device *dev,
- struct heci_msg_hdr *header,
- unsigned char *write_buffer,
- unsigned long write_length);
-
-int host_buffer_is_empty(struct iamt_heci_device *dev);
-
-__s32 count_full_read_slots(struct iamt_heci_device *dev);
-
-__s32 count_empty_write_slots(const struct iamt_heci_device *dev);
-
-int flow_ctrl_creds(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-
-int heci_send_wd(struct iamt_heci_device *dev);
-
-void flow_ctrl_reduce(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-
-int heci_send_flow_control(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-
-int heci_disconnect(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-int other_client_is_connecting(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-int heci_connect(struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-
-#endif /* _HECI_INTERFACE_H_ */
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/aio.h>
-#include <linux/pci.h>
-#include <linux/reboot.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/ioctl.h>
-#include <linux/cdev.h>
-#include <linux/device.h>
-#include <linux/unistd.h>
-#include <linux/kthread.h>
-
-#include "heci.h"
-#include "heci_interface.h"
-#include "heci_version.h"
-
-
-#define HECI_READ_TIMEOUT 45
-
-#define HECI_DRIVER_NAME "heci"
-
-/*
- * heci driver strings
- */
-static char heci_driver_name[] = HECI_DRIVER_NAME;
-static char heci_driver_string[] = "Intel(R) Management Engine Interface";
-static char heci_driver_version[] = HECI_DRIVER_VERSION;
-static char heci_copyright[] = "Copyright (c) 2003 - 2008 Intel Corporation.";
-
-
-#ifdef HECI_DEBUG
-int heci_debug = 1;
-#else
-int heci_debug;
-#endif
-MODULE_PARM_DESC(heci_debug, "Debug enabled or not");
-module_param(heci_debug, int, 0644);
-
-
-#define HECI_DEV_NAME "heci"
-
-/* heci char device for registration */
-static struct cdev heci_cdev;
-
-/* major number for device */
-static int heci_major;
-/* The device pointer */
-static struct pci_dev *heci_device;
-
-static struct class *heci_class;
-
-
-/* heci_pci_tbl - PCI Device ID Table */
-static struct pci_device_id heci_pci_tbl[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82946GZ)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82G35)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82Q965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82G965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82GM965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82GME965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82Q35)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82G33)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82Q33)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82X38)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_3200)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_6)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_7)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_8)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_9)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_10)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_3)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_3)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_4)},
- /* required last entry */
- {0, }
-};
-
-MODULE_DEVICE_TABLE(pci, heci_pci_tbl);
-
-/*
- * Local Function Prototypes
- */
-static int __init heci_init_module(void);
-static void __exit heci_exit_module(void);
-static int __devinit heci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static void __devexit heci_remove(struct pci_dev *pdev);
-static int heci_open(struct inode *inode, struct file *file);
-static int heci_release(struct inode *inode, struct file *file);
-static ssize_t heci_read(struct file *file, char __user *ubuf,
- size_t length, loff_t *offset);
-static int heci_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long data);
-static ssize_t heci_write(struct file *file, const char __user *ubuf,
- size_t length, loff_t *offset);
-static unsigned int heci_poll(struct file *file, poll_table *wait);
-static struct heci_cb_private *find_read_list_entry(
- struct iamt_heci_device *dev,
- struct heci_file_private *file_ext);
-#ifdef CONFIG_PM
-static int heci_suspend(struct pci_dev *pdev, pm_message_t state);
-static int heci_resume(struct pci_dev *pdev);
-static __u16 g_sus_wd_timeout;
-#else
-#define heci_suspend NULL
-#define heci_resume NULL
-#endif
-/*
- * PCI driver structure
- */
-static struct pci_driver heci_driver = {
- .name = heci_driver_name,
- .id_table = heci_pci_tbl,
- .probe = heci_probe,
- .remove = __devexit_p(heci_remove),
- .shutdown = __devexit_p(heci_remove),
- .suspend = heci_suspend,
- .resume = heci_resume
-};
-
-/*
- * file operations structure will be use heci char device.
- */
-static const struct file_operations heci_fops = {
- .owner = THIS_MODULE,
- .read = heci_read,
- .ioctl = heci_ioctl,
- .open = heci_open,
- .release = heci_release,
- .write = heci_write,
- .poll = heci_poll,
-};
-
-/**
- * heci_registration_cdev - set up the cdev structure for heci device.
- *
- * @dev: char device struct
- * @hminor: minor number for registration char device
- * @fops: file operations structure
- *
- * returns 0 on success, <0 on failure.
- */
-static int heci_registration_cdev(struct cdev *dev, int hminor,
- const struct file_operations *fops)
-{
- int ret, devno = MKDEV(heci_major, hminor);
-
- cdev_init(dev, fops);
- dev->owner = THIS_MODULE;
- ret = cdev_add(dev, devno, 1);
- /* Fail gracefully if need be */
- if (ret) {
- printk(KERN_ERR "heci: Error %d registering heci device %d\n",
- ret, hminor);
- }
- return ret;
-}
-
-/* Display the version of heci driver. */
-static ssize_t version_show(struct class *dev, char *buf)
-{
- return sprintf(buf, "%s %s.\n",
- heci_driver_string, heci_driver_version);
-}
-
-static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
-
-/**
- * heci_register_cdev - registers heci char device
- *
- * returns 0 on success, <0 on failure.
- */
-static int heci_register_cdev(void)
-{
- int ret;
- dev_t dev;
-
- /* registration of char devices */
- ret = alloc_chrdev_region(&dev, HECI_MINORS_BASE, HECI_MINORS_COUNT,
- HECI_DRIVER_NAME);
- if (ret) {
- printk(KERN_ERR "heci: Error allocating char device region.\n");
- return ret;
- }
-
- heci_major = MAJOR(dev);
-
- ret = heci_registration_cdev(&heci_cdev, HECI_MINOR_NUMBER,
- &heci_fops);
- if (ret)
- unregister_chrdev_region(MKDEV(heci_major, HECI_MINORS_BASE),
- HECI_MINORS_COUNT);
-
- return ret;
-}
-
-/**
- * heci_unregister_cdev - unregisters heci char device
- */
-static void heci_unregister_cdev(void)
-{
- cdev_del(&heci_cdev);
- unregister_chrdev_region(MKDEV(heci_major, HECI_MINORS_BASE),
- HECI_MINORS_COUNT);
-}
-
-#ifndef HECI_DEVICE_CREATE
-#define HECI_DEVICE_CREATE device_create
-#endif
-/**
- * heci_sysfs_device_create - adds device entry to sysfs
- *
- * returns 0 on success, <0 on failure.
- */
-static int heci_sysfs_device_create(void)
-{
- struct class *class;
- void *tmphdev;
- int err = 0;
-
- class = class_create(THIS_MODULE, HECI_DRIVER_NAME);
- if (IS_ERR(class)) {
- err = PTR_ERR(class);
- printk(KERN_ERR "heci: Error creating heci class.\n");
- goto err_out;
- }
-
- err = class_create_file(class, &class_attr_version);
- if (err) {
- class_destroy(class);
- printk(KERN_ERR "heci: Error creating heci class file.\n");
- goto err_out;
- }
-
- tmphdev = HECI_DEVICE_CREATE(class, NULL, heci_cdev.dev, NULL,
- HECI_DEV_NAME);
- if (IS_ERR(tmphdev)) {
- err = PTR_ERR(tmphdev);
- class_remove_file(class, &class_attr_version);
- class_destroy(class);
- goto err_out;
- }
-
- heci_class = class;
-err_out:
- return err;
-}
-
-/**
- * heci_sysfs_device_remove - unregisters the device entry on sysfs
- */
-static void heci_sysfs_device_remove(void)
-{
- if ((heci_class == NULL) || (IS_ERR(heci_class)))
- return;
-
- device_destroy(heci_class, heci_cdev.dev);
- class_remove_file(heci_class, &class_attr_version);
- class_destroy(heci_class);
-}
-
-/**
- * heci_init_module - Driver Registration Routine
- *
- * heci_init_module is the first routine called when the driver is
- * loaded. All it does is register with the PCI subsystem.
- *
- * returns 0 on success, <0 on failure.
- */
-static int __init heci_init_module(void)
-{
- int ret = 0;
-
- printk(KERN_INFO "heci: %s - version %s\n", heci_driver_string,
- heci_driver_version);
- printk(KERN_INFO "heci: %s\n", heci_copyright);
-
- /* init pci module */
- ret = pci_register_driver(&heci_driver);
- if (ret < 0) {
- printk(KERN_ERR "heci: Error registering driver.\n");
- goto end;
- }
-
- ret = heci_register_cdev();
- if (ret)
- goto unregister_pci;
-
- ret = heci_sysfs_device_create();
- if (ret)
- goto unregister_cdev;
-
- return ret;
-
-unregister_cdev:
- heci_unregister_cdev();
-unregister_pci:
- pci_unregister_driver(&heci_driver);
-end:
- return ret;
-}
-
-module_init(heci_init_module);
-
-
-/**
- * heci_exit_module - Driver Exit Cleanup Routine
- *
- * heci_exit_module is called just before the driver is removed
- * from memory.
- */
-static void __exit heci_exit_module(void)
-{
- pci_unregister_driver(&heci_driver);
- heci_sysfs_device_remove();
- heci_unregister_cdev();
-}
-
-module_exit(heci_exit_module);
-
-
-/**
- * heci_probe - Device Initialization Routine
- *
- * @pdev: PCI device information struct
- * @ent: entry in kcs_pci_tbl
- *
- * returns 0 on success, <0 on failure.
- */
-static int __devinit heci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct iamt_heci_device *dev = NULL;
- int i, err = 0;
-
- if (heci_device) {
- err = -EEXIST;
- goto end;
- }
- /* enable pci dev */
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR "heci: Failed to enable pci device.\n");
- goto end;
- }
- /* set PCI host mastering */
- pci_set_master(pdev);
- /* pci request regions for heci driver */
- err = pci_request_regions(pdev, heci_driver_name);
- if (err) {
- printk(KERN_ERR "heci: Failed to get pci regions.\n");
- goto disable_device;
- }
- /* allocates and initializes the heci dev structure */
- dev = init_heci_device(pdev);
- if (!dev) {
- err = -ENOMEM;
- goto release_regions;
- }
- /* mapping IO device memory */
- for (i = 0; i <= 5; i++) {
- if (pci_resource_len(pdev, i) == 0)
- continue;
- if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
- printk(KERN_ERR "heci: heci has IO ports.\n");
- goto free_device;
- } else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
- if (dev->mem_base) {
- printk(KERN_ERR
- "heci: Too many mem addresses.\n");
- goto free_device;
- }
- dev->mem_base = pci_resource_start(pdev, i);
- dev->mem_length = pci_resource_len(pdev, i);
- }
- }
- if (!dev->mem_base) {
- printk(KERN_ERR "heci: No address to use.\n");
- err = -ENODEV;
- goto free_device;
- }
- dev->mem_addr = ioremap_nocache(dev->mem_base,
- dev->mem_length);
- if (!dev->mem_addr) {
- printk(KERN_ERR "heci: Remap IO device memory failure.\n");
- err = -ENOMEM;
- goto free_device;
- }
- /* request and enable interrupt */
- err = request_irq(pdev->irq, heci_isr_interrupt, IRQF_SHARED,
- heci_driver_name, dev);
- if (err) {
- printk(KERN_ERR "heci: Request_irq failure. irq = %d \n",
- pdev->irq);
- goto unmap_memory;
- }
-
- if (heci_hw_init(dev)) {
- printk(KERN_ERR "heci: Init hw failure.\n");
- err = -ENODEV;
- goto release_irq;
- }
- init_timer(&dev->wd_timer);
-
- heci_initialize_clients(dev);
- if (dev->heci_state != HECI_ENABLED) {
- err = -ENODEV;
- goto release_hw;
- }
-
- spin_lock_bh(&dev->device_lock);
- heci_device = pdev;
- pci_set_drvdata(pdev, dev);
- spin_unlock_bh(&dev->device_lock);
-
- if (dev->wd_timeout)
- mod_timer(&dev->wd_timer, jiffies);
-
-#ifdef CONFIG_PM
- g_sus_wd_timeout = 0;
-#endif
- printk(KERN_INFO "heci driver initialization successful.\n");
- return 0;
-
-release_hw:
- /* disable interrupts */
- dev->host_hw_state = read_heci_register(dev, H_CSR);
- heci_csr_disable_interrupts(dev);
-
- del_timer_sync(&dev->wd_timer);
-
- flush_scheduled_work();
-
-release_irq:
- free_irq(pdev->irq, dev);
-unmap_memory:
- if (dev->mem_addr)
- iounmap(dev->mem_addr);
-free_device:
- kfree(dev);
-release_regions:
- pci_release_regions(pdev);
-disable_device:
- pci_disable_device(pdev);
-end:
- printk(KERN_ERR "heci driver initialization failed.\n");
- return err;
-}
-
-/**
- * heci_remove - Device Removal Routine
- *
- * @pdev: PCI device information struct
- *
- * heci_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.
- */
-static void __devexit heci_remove(struct pci_dev *pdev)
-{
- struct iamt_heci_device *dev = pci_get_drvdata(pdev);
-
- if (heci_device != pdev)
- return;
-
- if (dev == NULL)
- return;
-
- spin_lock_bh(&dev->device_lock);
- if (heci_device != pdev) {
- spin_unlock_bh(&dev->device_lock);
- return;
- }
-
- if (dev->reinit_tsk != NULL) {
- kthread_stop(dev->reinit_tsk);
- dev->reinit_tsk = NULL;
- }
-
- del_timer_sync(&dev->wd_timer);
- if (dev->wd_file_ext.state == HECI_FILE_CONNECTED
- && dev->wd_timeout) {
- dev->wd_timeout = 0;
- dev->wd_due_counter = 0;
- memcpy(dev->wd_data, heci_stop_wd_params, HECI_WD_PARAMS_SIZE);
- dev->stop = 1;
- if (dev->host_buffer_is_empty &&
- flow_ctrl_creds(dev, &dev->wd_file_ext)) {
- dev->host_buffer_is_empty = 0;
-
- if (!heci_send_wd(dev))
- DBG("send stop WD failed\n");
- else
- flow_ctrl_reduce(dev, &dev->wd_file_ext);
-
- dev->wd_pending = 0;
- } else {
- dev->wd_pending = 1;
- }
- dev->wd_stoped = 0;
- spin_unlock_bh(&dev->device_lock);
-
- wait_event_interruptible_timeout(dev->wait_stop_wd,
- (dev->wd_stoped), 10 * HZ);
- spin_lock_bh(&dev->device_lock);
- if (!dev->wd_stoped)
- DBG("stop wd failed to complete.\n");
- else
- DBG("stop wd complete.\n");
-
- }
-
- heci_device = NULL;
- spin_unlock_bh(&dev->device_lock);
-
- if (dev->iamthif_file_ext.state == HECI_FILE_CONNECTED) {
- dev->iamthif_file_ext.state = HECI_FILE_DISCONNECTING;
- heci_disconnect_host_client(dev,
- &dev->iamthif_file_ext);
- }
- if (dev->wd_file_ext.state == HECI_FILE_CONNECTED) {
- dev->wd_file_ext.state = HECI_FILE_DISCONNECTING;
- heci_disconnect_host_client(dev,
- &dev->wd_file_ext);
- }
-
- spin_lock_bh(&dev->device_lock);
-
- /* remove entry if already in list */
- DBG("list del iamthif and wd file list.\n");
- heci_remove_client_from_file_list(dev, dev->wd_file_ext.
- host_client_id);
- heci_remove_client_from_file_list(dev,
- dev->iamthif_file_ext.host_client_id);
-
- dev->iamthif_current_cb = NULL;
- dev->iamthif_file_ext.file = NULL;
- dev->num_heci_me_clients = 0;
-
- spin_unlock_bh(&dev->device_lock);
-
- flush_scheduled_work();
-
- /* disable interrupts */
- heci_csr_disable_interrupts(dev);
-
- free_irq(pdev->irq, dev);
- pci_set_drvdata(pdev, NULL);
-
- if (dev->mem_addr)
- iounmap(dev->mem_addr);
-
- kfree(dev);
-
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-/**
- * heci_clear_list - remove all callbacks associated with file
- * from heci_cb_list
- *
- * @file: file information struct
- * @heci_cb_list: callbacks list
- *
- * heci_clear_list is called to clear resources associated with file
- * when application calls close function or Ctrl-C was pressed
- *
- * returns 1 if callback removed from the list, 0 otherwise
- */
-static int heci_clear_list(struct iamt_heci_device *dev,
- struct file *file, struct list_head *heci_cb_list)
-{
- struct heci_cb_private *priv_cb_pos = NULL;
- struct heci_cb_private *priv_cb_next = NULL;
- struct file *file_temp;
- int rets = 0;
-
- /* list all list member */
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- heci_cb_list, cb_list) {
- file_temp = (struct file *)priv_cb_pos->file_object;
- /* check if list member associated with a file */
- if (file_temp == file) {
- /* remove member from the list */
- list_del(&priv_cb_pos->cb_list);
- /* check if cb equal to current iamthif cb */
- if (dev->iamthif_current_cb == priv_cb_pos) {
- dev->iamthif_current_cb = NULL;
- /* send flow control to iamthif client */
- heci_send_flow_control(dev,
- &dev->iamthif_file_ext);
- }
- /* free all allocated buffers */
- heci_free_cb_private(priv_cb_pos);
- rets = 1;
- }
- }
- return rets;
-}
-
-/**
- * heci_clear_lists - remove all callbacks associated with file
- *
- * @dev: device information struct
- * @file: file information struct
- *
- * heci_clear_lists is called to clear resources associated with file
- * when application calls close function or Ctrl-C was pressed
- *
- * returns 1 if callback removed from the list, 0 otherwise
- */
-static int heci_clear_lists(struct iamt_heci_device *dev, struct file *file)
-{
- int rets = 0;
-
- /* remove callbacks associated with a file */
- heci_clear_list(dev, file, &dev->pthi_cmd_list.heci_cb.cb_list);
- if (heci_clear_list(dev, file,
- &dev->pthi_read_complete_list.heci_cb.cb_list))
- rets = 1;
-
- heci_clear_list(dev, file, &dev->ctrl_rd_list.heci_cb.cb_list);
-
- if (heci_clear_list(dev, file, &dev->ctrl_wr_list.heci_cb.cb_list))
- rets = 1;
-
- if (heci_clear_list(dev, file,
- &dev->write_waiting_list.heci_cb.cb_list))
- rets = 1;
-
- if (heci_clear_list(dev, file, &dev->write_list.heci_cb.cb_list))
- rets = 1;
-
- /* check if iamthif_current_cb not NULL */
- if (dev->iamthif_current_cb && (!rets)) {
- /* check file and iamthif current cb association */
- if (dev->iamthif_current_cb->file_object == file) {
- /* remove cb */
- heci_free_cb_private(dev->iamthif_current_cb);
- dev->iamthif_current_cb = NULL;
- rets = 1;
- }
- }
- return rets;
-}
-
-/**
- * heci_open - the open function
- *
- * @inode: pointer to inode structure
- * @file: pointer to file structure
- *
- * returns 0 on success, <0 on error
- */
-static int heci_open(struct inode *inode, struct file *file)
-{
- struct heci_file_private *file_ext;
- int if_num = iminor(inode);
- struct iamt_heci_device *dev;
-
- if (!heci_device)
- return -ENODEV;
-
- dev = pci_get_drvdata(heci_device);
- if ((if_num != HECI_MINOR_NUMBER) || (!dev))
- return -ENODEV;
-
- file_ext = heci_alloc_file_private(file);
- if (file_ext == NULL)
- return -ENOMEM;
-
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state != HECI_ENABLED) {
- spin_unlock_bh(&dev->device_lock);
- kfree(file_ext);
- return -ENODEV;
- }
- if (dev->open_handle_count >= HECI_MAX_OPEN_HANDLE_COUNT) {
- spin_unlock_bh(&dev->device_lock);
- kfree(file_ext);
- return -ENFILE;
- };
- dev->open_handle_count++;
- list_add_tail(&file_ext->link, &dev->file_list);
- while ((dev->heci_host_clients[dev->current_host_client_id / 8]
- & (1 << (dev->current_host_client_id % 8))) != 0) {
-
- dev->current_host_client_id++; /* allow overflow */
- DBG("current_host_client_id = %d\n",
- dev->current_host_client_id);
- DBG("dev->open_handle_count = %lu\n",
- dev->open_handle_count);
- }
- DBG("current_host_client_id = %d\n", dev->current_host_client_id);
- file_ext->host_client_id = dev->current_host_client_id;
- dev->heci_host_clients[file_ext->host_client_id / 8] |=
- (1 << (file_ext->host_client_id % 8));
- spin_unlock_bh(&dev->device_lock);
- spin_lock(&file_ext->file_lock);
- spin_lock_bh(&dev->device_lock);
- file_ext->state = HECI_FILE_INITIALIZING;
- spin_unlock_bh(&dev->device_lock);
- file_ext->sm_state = 0;
-
- file->private_data = file_ext;
- spin_unlock(&file_ext->file_lock);
-
- return 0;
-}
-
-/**
- * heci_release - the release function
- *
- * @inode: pointer to inode structure
- * @file: pointer to file structure
- *
- * returns 0 on success, <0 on error
- */
-static int heci_release(struct inode *inode, struct file *file)
-{
- int rets = 0;
- int if_num = iminor(inode);
- struct heci_file_private *file_ext = file->private_data;
- struct heci_cb_private *priv_cb = NULL;
- struct iamt_heci_device *dev;
-
- if (!heci_device)
- return -ENODEV;
-
- dev = pci_get_drvdata(heci_device);
- if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
- return -ENODEV;
-
- if (file_ext != &dev->iamthif_file_ext) {
- spin_lock(&file_ext->file_lock);
- spin_lock_bh(&dev->device_lock);
- if (file_ext->state == HECI_FILE_CONNECTED) {
- file_ext->state = HECI_FILE_DISCONNECTING;
- spin_unlock_bh(&dev->device_lock);
- spin_unlock(&file_ext->file_lock);
- DBG("disconnecting client host client = %d, "
- "ME client = %d\n",
- file_ext->host_client_id,
- file_ext->me_client_id);
- rets = heci_disconnect_host_client(dev, file_ext);
- spin_lock(&file_ext->file_lock);
- spin_lock_bh(&dev->device_lock);
- }
- heci_flush_queues(dev, file_ext);
- DBG("remove client host client = %d, ME client = %d\n",
- file_ext->host_client_id,
- file_ext->me_client_id);
-
- if (dev->open_handle_count > 0) {
- dev->heci_host_clients[file_ext->host_client_id / 8] &=
- ~(1 << (file_ext->host_client_id % 8));
- dev->open_handle_count--;
- }
- heci_remove_client_from_file_list(dev,
- file_ext->host_client_id);
-
- /* free read cb */
- if (file_ext->read_cb != NULL) {
- priv_cb = find_read_list_entry(dev, file_ext);
- /* Remove entry from read list */
- if (priv_cb != NULL)
- list_del(&priv_cb->cb_list);
-
- priv_cb = file_ext->read_cb;
- file_ext->read_cb = NULL;
- }
-
- spin_unlock_bh(&dev->device_lock);
- file->private_data = NULL;
- spin_unlock(&file_ext->file_lock);
-
- if (priv_cb != NULL)
- heci_free_cb_private(priv_cb);
-
- kfree(file_ext);
- } else {
- spin_lock_bh(&dev->device_lock);
-
- if (dev->open_handle_count > 0)
- dev->open_handle_count--;
-
- if (dev->iamthif_file_object == file
- && dev->iamthif_state != HECI_IAMTHIF_IDLE) {
- DBG("pthi canceled iamthif state %d\n",
- dev->iamthif_state);
- dev->iamthif_canceled = 1;
- if (dev->iamthif_state == HECI_IAMTHIF_READ_COMPLETE) {
- DBG("run next pthi iamthif cb\n");
- run_next_iamthif_cmd(dev);
- }
- }
-
- if (heci_clear_lists(dev, file))
- dev->iamthif_state = HECI_IAMTHIF_IDLE;
-
- spin_unlock_bh(&dev->device_lock);
- }
- return rets;
-}
-
-static struct heci_cb_private *find_read_list_entry(
- struct iamt_heci_device *dev,
- struct heci_file_private *file_ext)
-{
- struct heci_cb_private *priv_cb_pos = NULL;
- struct heci_cb_private *priv_cb_next = NULL;
- struct heci_file_private *file_ext_list_temp;
-
- if (dev->read_list.status == 0
- && !list_empty(&dev->read_list.heci_cb.cb_list)) {
- DBG("remove read_list CB \n");
- list_for_each_entry_safe(priv_cb_pos,
- priv_cb_next,
- &dev->read_list.heci_cb.cb_list, cb_list) {
-
- file_ext_list_temp = (struct heci_file_private *)
- priv_cb_pos->file_private;
-
- if ((file_ext_list_temp != NULL) &&
- heci_fe_same_id(file_ext, file_ext_list_temp))
- return priv_cb_pos;
-
- }
- }
- return NULL;
-}
-
-/**
- * heci_read - the read client message function.
- *
- * @file: pointer to file structure
- * @ubuf: pointer to user buffer
- * @length: buffer length
- * @offset: data offset in buffer
- *
- * returns >=0 data length on success , <0 on error
- */
-static ssize_t heci_read(struct file *file, char __user *ubuf,
- size_t length, loff_t *offset)
-{
- int i;
- int rets = 0, err = 0;
- int if_num = iminor(file->f_dentry->d_inode);
- struct heci_file_private *file_ext = file->private_data;
- struct heci_cb_private *priv_cb_pos = NULL;
- struct heci_cb_private *priv_cb = NULL;
- struct iamt_heci_device *dev;
-
- if (!heci_device)
- return -ENODEV;
-
- dev = pci_get_drvdata(heci_device);
- if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
- return -ENODEV;
-
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state != HECI_ENABLED) {
- spin_unlock_bh(&dev->device_lock);
- return -ENODEV;
- }
- spin_unlock_bh(&dev->device_lock);
-
- spin_lock(&file_ext->file_lock);
- if ((file_ext->sm_state & HECI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
- spin_unlock(&file_ext->file_lock);
- /* Do not allow to read watchdog client */
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (memcmp(&heci_wd_guid,
- &dev->me_clients[i].props.protocol_name,
- sizeof(struct guid)) == 0) {
- if (file_ext->me_client_id ==
- dev->me_clients[i].client_id)
- return -EBADF;
- }
- }
- } else {
- file_ext->sm_state &= ~HECI_WD_STATE_INDEPENDENCE_MSG_SENT;
- spin_unlock(&file_ext->file_lock);
- }
-
- if (file_ext == &dev->iamthif_file_ext) {
- rets = pthi_read(dev, if_num, file, ubuf, length, offset);
- goto out;
- }
-
- if (file_ext->read_cb && file_ext->read_cb->information > *offset) {
- priv_cb = file_ext->read_cb;
- goto copy_buffer;
- } else if (file_ext->read_cb && file_ext->read_cb->information > 0 &&
- file_ext->read_cb->information <= *offset) {
- priv_cb = file_ext->read_cb;
- rets = 0;
- goto free;
- } else if ((!file_ext->read_cb || file_ext->read_cb->information == 0)
- && *offset > 0) {
- /*Offset needs to be cleaned for contingous reads*/
- *offset = 0;
- rets = 0;
- goto out;
- }
-
- err = heci_start_read(dev, if_num, file_ext);
- spin_lock_bh(&file_ext->read_io_lock);
- if (err != 0 && err != -EBUSY) {
- DBG("heci start read failure with status = %d\n", err);
- spin_unlock_bh(&file_ext->read_io_lock);
- rets = err;
- goto out;
- }
- if (HECI_READ_COMPLETE != file_ext->reading_state
- && !waitqueue_active(&file_ext->rx_wait)) {
- if (file->f_flags & O_NONBLOCK) {
- rets = -EAGAIN;
- spin_unlock_bh(&file_ext->read_io_lock);
- goto out;
- }
- spin_unlock_bh(&file_ext->read_io_lock);
-
- if (wait_event_interruptible(file_ext->rx_wait,
- (HECI_READ_COMPLETE == file_ext->reading_state
- || HECI_FILE_INITIALIZING == file_ext->state
- || HECI_FILE_DISCONNECTED == file_ext->state
- || HECI_FILE_DISCONNECTING == file_ext->state))) {
- if (signal_pending(current)) {
- rets = -EINTR;
- goto out;
- }
- return -ERESTARTSYS;
- }
-
- spin_lock_bh(&dev->device_lock);
- if (HECI_FILE_INITIALIZING == file_ext->state ||
- HECI_FILE_DISCONNECTED == file_ext->state ||
- HECI_FILE_DISCONNECTING == file_ext->state) {
- spin_unlock_bh(&dev->device_lock);
- rets = -EBUSY;
- goto out;
- }
- spin_unlock_bh(&dev->device_lock);
- spin_lock_bh(&file_ext->read_io_lock);
- }
-
- priv_cb = file_ext->read_cb;
-
- if (!priv_cb) {
- spin_unlock_bh(&file_ext->read_io_lock);
- return -ENODEV;
- }
- if (file_ext->reading_state != HECI_READ_COMPLETE) {
- spin_unlock_bh(&file_ext->read_io_lock);
- return 0;
- }
- spin_unlock_bh(&file_ext->read_io_lock);
- /* now copy the data to user space */
-copy_buffer:
- DBG("priv_cb->response_buffer size - %d\n",
- priv_cb->response_buffer.size);
- DBG("priv_cb->information - %lu\n",
- priv_cb->information);
- if (length == 0 || ubuf == NULL ||
- *offset > priv_cb->information) {
- rets = -EMSGSIZE;
- goto free;
- }
-
- /* length is being turncated to PAGE_SIZE, however, */
- /* information size may be longer */
- length = (length < (priv_cb->information - *offset) ?
- length : (priv_cb->information - *offset));
-
- if (copy_to_user(ubuf,
- priv_cb->response_buffer.data + *offset,
- length)) {
- rets = -EFAULT;
- goto free;
- }
-
- rets = length;
- *offset += length;
- if ((unsigned long)*offset < priv_cb->information)
- goto out;
-
-free:
- spin_lock_bh(&dev->device_lock);
- priv_cb_pos = find_read_list_entry(dev, file_ext);
- /* Remove entry from read list */
- if (priv_cb_pos != NULL)
- list_del(&priv_cb_pos->cb_list);
- spin_unlock_bh(&dev->device_lock);
- heci_free_cb_private(priv_cb);
- spin_lock_bh(&file_ext->read_io_lock);
- file_ext->reading_state = HECI_IDLE;
- file_ext->read_cb = NULL;
- file_ext->read_pending = 0;
- spin_unlock_bh(&file_ext->read_io_lock);
-out: DBG("end heci read rets= %d\n", rets);
- return rets;
-}
-
-/**
- * heci_write - the write function.
- *
- * @file: pointer to file structure
- * @ubuf: pointer to user buffer
- * @length: buffer length
- * @offset: data offset in buffer
- *
- * returns >=0 data length on success , <0 on error
- */
-static ssize_t heci_write(struct file *file, const char __user *ubuf,
- size_t length, loff_t *offset)
-{
- int rets = 0;
- __u8 i;
- int if_num = iminor(file->f_dentry->d_inode);
- struct heci_file_private *file_ext = file->private_data;
- struct heci_cb_private *priv_write_cb = NULL;
- struct heci_msg_hdr heci_hdr;
- struct iamt_heci_device *dev;
- unsigned long currtime = get_seconds();
-
- if (!heci_device)
- return -ENODEV;
-
- dev = pci_get_drvdata(heci_device);
-
- if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
- return -ENODEV;
-
- spin_lock_bh(&dev->device_lock);
-
- if (dev->heci_state != HECI_ENABLED) {
- spin_unlock_bh(&dev->device_lock);
- return -ENODEV;
- }
- if (file_ext == &dev->iamthif_file_ext) {
- priv_write_cb = find_pthi_read_list_entry(dev, file);
- if ((priv_write_cb != NULL) &&
- (((currtime - priv_write_cb->read_time) >=
- IAMTHIF_READ_TIMER) ||
- (file_ext->reading_state == HECI_READ_COMPLETE))) {
- (*offset) = 0;
- list_del(&priv_write_cb->cb_list);
- heci_free_cb_private(priv_write_cb);
- priv_write_cb = NULL;
- }
- }
-
- /* free entry used in read */
- if (file_ext->reading_state == HECI_READ_COMPLETE) {
- *offset = 0;
- priv_write_cb = find_read_list_entry(dev, file_ext);
- if (priv_write_cb != NULL) {
- list_del(&priv_write_cb->cb_list);
- heci_free_cb_private(priv_write_cb);
- priv_write_cb = NULL;
- spin_lock_bh(&file_ext->read_io_lock);
- file_ext->reading_state = HECI_IDLE;
- file_ext->read_cb = NULL;
- file_ext->read_pending = 0;
- spin_unlock_bh(&file_ext->read_io_lock);
- }
- } else if (file_ext->reading_state == HECI_IDLE &&
- file_ext->read_pending == 0)
- (*offset) = 0;
-
- spin_unlock_bh(&dev->device_lock);
-
- priv_write_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
- if (!priv_write_cb)
- return -ENOMEM;
-
- priv_write_cb->file_object = file;
- priv_write_cb->file_private = file_ext;
- priv_write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
- if (!priv_write_cb->request_buffer.data) {
- kfree(priv_write_cb);
- return -ENOMEM;
- }
- DBG("length =%d\n", (int) length);
-
- if (copy_from_user(priv_write_cb->request_buffer.data,
- ubuf, length)) {
- rets = -EFAULT;
- goto fail;
- }
-
- spin_lock(&file_ext->file_lock);
- file_ext->sm_state = 0;
- if ((length == 4) &&
- ((memcmp(heci_wd_state_independence_msg[0],
- priv_write_cb->request_buffer.data, 4) == 0) ||
- (memcmp(heci_wd_state_independence_msg[1],
- priv_write_cb->request_buffer.data, 4) == 0) ||
- (memcmp(heci_wd_state_independence_msg[2],
- priv_write_cb->request_buffer.data, 4) == 0)))
- file_ext->sm_state |= HECI_WD_STATE_INDEPENDENCE_MSG_SENT;
- spin_unlock(&file_ext->file_lock);
-
- INIT_LIST_HEAD(&priv_write_cb->cb_list);
- if (file_ext == &dev->iamthif_file_ext) {
- priv_write_cb->response_buffer.data =
- kmalloc(IAMTHIF_MTU, GFP_KERNEL);
- if (!priv_write_cb->response_buffer.data) {
- rets = -ENOMEM;
- goto fail;
- }
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state != HECI_ENABLED) {
- spin_unlock_bh(&dev->device_lock);
- rets = -ENODEV;
- goto fail;
- }
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (dev->me_clients[i].client_id ==
- dev->iamthif_file_ext.me_client_id)
- break;
- }
-
- BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id);
- if ((i == dev->num_heci_me_clients) ||
- (dev->me_clients[i].client_id !=
- dev->iamthif_file_ext.me_client_id)) {
-
- spin_unlock_bh(&dev->device_lock);
- rets = -ENODEV;
- goto fail;
- } else if ((length > dev->me_clients[i].props.max_msg_length)
- || (length <= 0)) {
- spin_unlock_bh(&dev->device_lock);
- rets = -EMSGSIZE;
- goto fail;
- }
-
-
- priv_write_cb->response_buffer.size = IAMTHIF_MTU;
- priv_write_cb->major_file_operations = HECI_IOCTL;
- priv_write_cb->information = 0;
- priv_write_cb->request_buffer.size = length;
- if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) {
- spin_unlock_bh(&dev->device_lock);
- rets = -ENODEV;
- goto fail;
- }
-
- if (!list_empty(&dev->pthi_cmd_list.heci_cb.cb_list)
- || dev->iamthif_state != HECI_IAMTHIF_IDLE) {
- DBG("pthi_state = %d\n", (int) dev->iamthif_state);
- DBG("add PTHI cb to pthi cmd waiting list\n");
- list_add_tail(&priv_write_cb->cb_list,
- &dev->pthi_cmd_list.heci_cb.cb_list);
- rets = length;
- } else {
- DBG("call pthi write\n");
- rets = pthi_write(dev, priv_write_cb);
-
- if (rets != 0) {
- DBG("pthi write failed with status = %d\n",
- rets);
- spin_unlock_bh(&dev->device_lock);
- goto fail;
- }
- rets = length;
- }
- spin_unlock_bh(&dev->device_lock);
- return rets;
- }
-
- priv_write_cb->major_file_operations = HECI_WRITE;
- /* make sure information is zero before we start */
-
- priv_write_cb->information = 0;
- priv_write_cb->request_buffer.size = length;
-
- spin_lock(&file_ext->write_io_lock);
- spin_lock_bh(&dev->device_lock);
- DBG("host client = %d, ME client = %d\n",
- file_ext->host_client_id, file_ext->me_client_id);
- if (file_ext->state != HECI_FILE_CONNECTED) {
- rets = -ENODEV;
- DBG("host client = %d, is not connected to ME client = %d",
- file_ext->host_client_id,
- file_ext->me_client_id);
- spin_unlock_bh(&dev->device_lock);
- goto unlock;
- }
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (dev->me_clients[i].client_id ==
- file_ext->me_client_id)
- break;
- }
- BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id);
- if (i == dev->num_heci_me_clients) {
- rets = -ENODEV;
- spin_unlock_bh(&dev->device_lock);
- goto unlock;
- }
- if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
- rets = -EINVAL;
- spin_unlock_bh(&dev->device_lock);
- goto unlock;
- }
- priv_write_cb->file_private = file_ext;
-
- if (flow_ctrl_creds(dev, file_ext) &&
- dev->host_buffer_is_empty) {
- spin_unlock_bh(&dev->device_lock);
- dev->host_buffer_is_empty = 0;
- if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
- sizeof(__u32)) - sizeof(struct heci_msg_hdr))) {
-
- heci_hdr.length =
- (((dev->host_hw_state & H_CBD) >> 24) *
- sizeof(__u32)) -
- sizeof(struct heci_msg_hdr);
- heci_hdr.msg_complete = 0;
- } else {
- heci_hdr.length = length;
- heci_hdr.msg_complete = 1;
- }
- heci_hdr.host_addr = file_ext->host_client_id;
- heci_hdr.me_addr = file_ext->me_client_id;
- heci_hdr.reserved = 0;
- DBG("call heci_write_message header=%08x.\n",
- *((__u32 *) &heci_hdr));
- spin_unlock(&file_ext->write_io_lock);
- /* protect heci low level write */
- spin_lock_bh(&dev->device_lock);
- if (!heci_write_message(dev, &heci_hdr,
- (unsigned char *) (priv_write_cb->request_buffer.data),
- heci_hdr.length)) {
-
- spin_unlock_bh(&dev->device_lock);
- heci_free_cb_private(priv_write_cb);
- rets = -ENODEV;
- priv_write_cb->information = 0;
- return rets;
- }
- file_ext->writing_state = HECI_WRITING;
- priv_write_cb->information = heci_hdr.length;
- if (heci_hdr.msg_complete) {
- flow_ctrl_reduce(dev, file_ext);
- list_add_tail(&priv_write_cb->cb_list,
- &dev->write_waiting_list.heci_cb.cb_list);
- } else {
- list_add_tail(&priv_write_cb->cb_list,
- &dev->write_list.heci_cb.cb_list);
- }
- spin_unlock_bh(&dev->device_lock);
-
- } else {
-
- spin_unlock_bh(&dev->device_lock);
- priv_write_cb->information = 0;
- file_ext->writing_state = HECI_WRITING;
- spin_unlock(&file_ext->write_io_lock);
- list_add_tail(&priv_write_cb->cb_list,
- &dev->write_list.heci_cb.cb_list);
- }
- return length;
-
-unlock:
- spin_unlock(&file_ext->write_io_lock);
-fail:
- heci_free_cb_private(priv_write_cb);
- return rets;
-
-}
-
-/**
- * heci_ioctl - the IOCTL function
- *
- * @inode: pointer to inode structure
- * @file: pointer to file structure
- * @cmd: ioctl command
- * @data: pointer to heci message structure
- *
- * returns 0 on success , <0 on error
- */
-static int heci_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long data)
-{
- int rets = 0;
- int if_num = iminor(inode);
- struct heci_file_private *file_ext = file->private_data;
- /* in user space */
- struct heci_message_data __user *u_msg;
- struct heci_message_data k_msg; /* all in kernel on the stack */
- struct iamt_heci_device *dev;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (!heci_device)
- return -ENODEV;
-
- dev = pci_get_drvdata(heci_device);
- if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
- return -ENODEV;
-
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state != HECI_ENABLED) {
- spin_unlock_bh(&dev->device_lock);
- return -ENODEV;
- }
- spin_unlock_bh(&dev->device_lock);
-
- /* first copy from user all data needed */
- u_msg = (struct heci_message_data __user *)data;
- if (copy_from_user(&k_msg, u_msg, sizeof(k_msg))) {
- DBG("first copy from user all data needed filled\n");
- return -EFAULT;
- }
- DBG("user message size is %d\n", k_msg.size);
-
- switch (cmd) {
- case IOCTL_HECI_GET_VERSION:
- DBG(": IOCTL_HECI_GET_VERSION\n");
- rets = heci_ioctl_get_version(dev, if_num, u_msg, k_msg,
- file_ext);
- break;
-
- case IOCTL_HECI_CONNECT_CLIENT:
- DBG(": IOCTL_HECI_CONNECT_CLIENT.\n");
- rets = heci_ioctl_connect_client(dev, if_num, u_msg, k_msg,
- file);
- break;
-
- case IOCTL_HECI_WD:
- DBG(": IOCTL_HECI_WD.\n");
- rets = heci_ioctl_wd(dev, if_num, k_msg, file_ext);
- break;
-
- case IOCTL_HECI_BYPASS_WD:
- DBG(": IOCTL_HECI_BYPASS_WD.\n");
- rets = heci_ioctl_bypass_wd(dev, if_num, k_msg, file_ext);
- break;
-
- default:
- rets = -EINVAL;
- break;
- }
- return rets;
-}
-
-/**
- * heci_poll - the poll function
- *
- * @file: pointer to file structure
- * @wait: pointer to poll_table structure
- *
- * returns poll mask
- */
-static unsigned int heci_poll(struct file *file, poll_table *wait)
-{
- int if_num = iminor(file->f_dentry->d_inode);
- unsigned int mask = 0;
- struct heci_file_private *file_ext = file->private_data;
- struct iamt_heci_device *dev;
-
- if (!heci_device)
- return mask;
-
- dev = pci_get_drvdata(heci_device);
-
- if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
- return mask;
-
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state != HECI_ENABLED) {
- spin_unlock_bh(&dev->device_lock);
- return mask;
- }
- spin_unlock_bh(&dev->device_lock);
-
- if (file_ext == &dev->iamthif_file_ext) {
- poll_wait(file, &dev->iamthif_file_ext.wait, wait);
- spin_lock(&dev->iamthif_file_ext.file_lock);
- if (dev->iamthif_state == HECI_IAMTHIF_READ_COMPLETE
- && dev->iamthif_file_object == file) {
- mask |= (POLLIN | POLLRDNORM);
- spin_lock_bh(&dev->device_lock);
- DBG("run next pthi cb\n");
- run_next_iamthif_cmd(dev);
- spin_unlock_bh(&dev->device_lock);
- }
- spin_unlock(&dev->iamthif_file_ext.file_lock);
-
- } else{
- poll_wait(file, &file_ext->tx_wait, wait);
- spin_lock(&file_ext->write_io_lock);
- if (HECI_WRITE_COMPLETE == file_ext->writing_state)
- mask |= (POLLIN | POLLRDNORM);
-
- spin_unlock(&file_ext->write_io_lock);
- }
-
- return mask;
-}
-
-#ifdef CONFIG_PM
-static int heci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct iamt_heci_device *dev = pci_get_drvdata(pdev);
- int err = 0;
-
- spin_lock_bh(&dev->device_lock);
- if (dev->reinit_tsk != NULL) {
- kthread_stop(dev->reinit_tsk);
- dev->reinit_tsk = NULL;
- }
- spin_unlock_bh(&dev->device_lock);
-
- /* Stop watchdog if exists */
- del_timer_sync(&dev->wd_timer);
- if (dev->wd_file_ext.state == HECI_FILE_CONNECTED
- && dev->wd_timeout) {
- spin_lock_bh(&dev->device_lock);
- g_sus_wd_timeout = dev->wd_timeout;
- dev->wd_timeout = 0;
- dev->wd_due_counter = 0;
- memcpy(dev->wd_data, heci_stop_wd_params,
- HECI_WD_PARAMS_SIZE);
- dev->stop = 1;
- if (dev->host_buffer_is_empty &&
- flow_ctrl_creds(dev, &dev->wd_file_ext)) {
- dev->host_buffer_is_empty = 0;
- if (!heci_send_wd(dev))
- DBG("send stop WD failed\n");
- else
- flow_ctrl_reduce(dev, &dev->wd_file_ext);
-
- dev->wd_pending = 0;
- } else {
- dev->wd_pending = 1;
- }
- spin_unlock_bh(&dev->device_lock);
- dev->wd_stoped = 0;
-
- err = wait_event_interruptible_timeout(dev->wait_stop_wd,
- (dev->wd_stoped),
- 10 * HZ);
- if (!dev->wd_stoped)
- DBG("stop wd failed to complete.\n");
- else {
- DBG("stop wd complete %d.\n", err);
- err = 0;
- }
- }
- /* Set new heci state */
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state == HECI_ENABLED ||
- dev->heci_state == HECI_RECOVERING_FROM_RESET) {
- dev->heci_state = HECI_POWER_DOWN;
- heci_reset(dev, 0);
- }
- spin_unlock_bh(&dev->device_lock);
-
- pci_save_state(pdev);
-
- pci_disable_device(pdev);
- free_irq(pdev->irq, dev);
-
- pci_set_power_state(pdev, PCI_D3hot);
-
- return err;
-}
-
-static int heci_resume(struct pci_dev *pdev)
-{
- struct iamt_heci_device *dev;
- int err = 0;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return -ENODEV;
-
- /* request and enable interrupt */
- err = request_irq(pdev->irq, heci_isr_interrupt, IRQF_SHARED,
- heci_driver_name, dev);
- if (err) {
- printk(KERN_ERR "heci: Request_irq failure. irq = %d \n",
- pdev->irq);
- return err;
- }
-
- spin_lock_bh(&dev->device_lock);
- dev->heci_state = HECI_POWER_UP;
- heci_reset(dev, 1);
- spin_unlock_bh(&dev->device_lock);
-
- /* Start watchdog if stopped in suspend */
- if (g_sus_wd_timeout != 0) {
- dev->wd_timeout = g_sus_wd_timeout;
-
- memcpy(dev->wd_data, heci_start_wd_params,
- HECI_WD_PARAMS_SIZE);
- memcpy(dev->wd_data + HECI_WD_PARAMS_SIZE,
- &dev->wd_timeout, sizeof(__u16));
- dev->wd_due_counter = 1;
-
- if (dev->wd_timeout)
- mod_timer(&dev->wd_timer, jiffies);
-
- g_sus_wd_timeout = 0;
- }
- return err;
-}
-#endif
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION(HECI_DRIVER_VERSION);
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-#ifndef HECI_VERSION_H
-#define HECI_VERSION_H
-
-#define MAJOR_VERSION 5
-#define MINOR_VERSION 0
-#define QUICK_FIX_NUMBER 0
-#define VER_BUILD 31
-
-#define HECI_DRV_VER1 __stringify(MAJOR_VERSION) "." __stringify(MINOR_VERSION)
-#define HECI_DRV_VER2 __stringify(QUICK_FIX_NUMBER) "." __stringify(VER_BUILD)
-
-#define HECI_DRIVER_VERSION HECI_DRV_VER1 "." HECI_DRV_VER2
-
-#endif
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-#include <linux/kthread.h>
-
-#include "heci.h"
-#include "heci_interface.h"
-
-/*
- * interrupt function prototypes
- */
-static void heci_bh_handler(struct work_struct *work);
-static int heci_bh_read_handler(struct io_heci_list *complete_list,
- struct iamt_heci_device *dev,
- __s32 *slots);
-static int heci_bh_write_handler(struct io_heci_list *complete_list,
- struct iamt_heci_device *dev,
- __s32 *slots);
-static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
- struct heci_msg_hdr *heci_hdr);
-static int heci_bh_read_pthi_message(struct io_heci_list *complete_list,
- struct iamt_heci_device *dev,
- struct heci_msg_hdr *heci_hdr);
-static int heci_bh_read_client_message(struct io_heci_list *complete_list,
- struct iamt_heci_device *dev,
- struct heci_msg_hdr *heci_hdr);
-static void heci_client_connect_response(struct iamt_heci_device *dev,
- struct hbm_client_connect_response *connect_res);
-static void heci_client_disconnect_response(struct iamt_heci_device *dev,
- struct hbm_client_connect_response *disconnect_res);
-static void heci_client_flow_control_response(struct iamt_heci_device *dev,
- struct hbm_flow_control *flow_control);
-static void heci_client_disconnect_request(struct iamt_heci_device *dev,
- struct hbm_client_disconnect_request *disconnect_req);
-
-
-/**
- * heci_isr_interrupt - The ISR of the HECI device
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- */
-irqreturn_t heci_isr_interrupt(int irq, void *dev_id)
-{
- int err;
- struct iamt_heci_device *dev = (struct iamt_heci_device *) dev_id;
-
- dev->host_hw_state = read_heci_register(dev, H_CSR);
-
- if ((dev->host_hw_state & H_IS) != H_IS)
- return IRQ_NONE;
-
- /* disable interrupts */
- heci_csr_disable_interrupts(dev);
-
- /* clear H_IS bit in H_CSR */
- heci_csr_clear_his(dev);
-
- /*
- * Our device interrupted, schedule work the heci_bh_handler
- * to handle the interrupt processing. This needs to be a
- * workqueue item since the handler can sleep.
- */
- PREPARE_WORK(&dev->work, heci_bh_handler);
- DBG("schedule work the heci_bh_handler.\n");
- err = schedule_work(&dev->work);
- if (!err)
- DBG("heci_bh_handler was already on the workqueue.\n");
- return IRQ_HANDLED;
-}
-
-/**
- * _heci_cmpl - process completed operation.
- *
- * @file_ext: private data of the file object.
- * @priv_cb_pos: callback block.
- */
-static void _heci_cmpl(struct heci_file_private *file_ext,
- struct heci_cb_private *priv_cb_pos)
-{
- if (priv_cb_pos->major_file_operations == HECI_WRITE) {
- heci_free_cb_private(priv_cb_pos);
- DBG("completing write call back.\n");
- file_ext->writing_state = HECI_WRITE_COMPLETE;
- if ((&file_ext->tx_wait) &&
- waitqueue_active(&file_ext->tx_wait))
- wake_up_interruptible(&file_ext->tx_wait);
-
- } else if (priv_cb_pos->major_file_operations == HECI_READ
- && HECI_READING == file_ext->reading_state) {
- DBG("completing read call back information= %lu\n",
- priv_cb_pos->information);
- file_ext->reading_state = HECI_READ_COMPLETE;
- if ((&file_ext->rx_wait) &&
- waitqueue_active(&file_ext->rx_wait))
- wake_up_interruptible(&file_ext->rx_wait);
-
- }
-}
-
-/**
- * _heci_cmpl_iamthif - process completed iamthif operation.
- *
- * @dev: Device object for our driver.
- * @priv_cb_pos: callback block.
- */
-static void _heci_cmpl_iamthif(struct iamt_heci_device *dev,
- struct heci_cb_private *priv_cb_pos)
-{
- if (dev->iamthif_canceled != 1) {
- dev->iamthif_state = HECI_IAMTHIF_READ_COMPLETE;
- dev->iamthif_stall_timer = 0;
- memcpy(priv_cb_pos->response_buffer.data,
- dev->iamthif_msg_buf,
- dev->iamthif_msg_buf_index);
- list_add_tail(&priv_cb_pos->cb_list,
- &dev->pthi_read_complete_list.heci_cb.cb_list);
- DBG("pthi read completed.\n");
- } else {
- run_next_iamthif_cmd(dev);
- }
- if (&dev->iamthif_file_ext.wait) {
- DBG("completing pthi call back.\n");
- wake_up_interruptible(&dev->iamthif_file_ext.wait);
- }
-}
-/**
- * heci_bh_handler - function called after ISR to handle the interrupt
- * processing.
- *
- * @work: pointer to the work structure
- *
- * NOTE: This function is called by schedule work
- */
-static void heci_bh_handler(struct work_struct *work)
-{
- struct iamt_heci_device *dev =
- container_of(work, struct iamt_heci_device, work);
- struct io_heci_list complete_list;
- __s32 slots;
- int rets;
- struct heci_cb_private *cb_pos = NULL, *cb_next = NULL;
- struct heci_file_private *file_ext;
- int bus_message_received = 0;
- struct task_struct *tsk;
-
- DBG("function called after ISR to handle the interrupt processing.\n");
- /* initialize our complete list */
- spin_lock_bh(&dev->device_lock);
- heci_initialize_list(&complete_list, dev);
- dev->host_hw_state = read_heci_register(dev, H_CSR);
- dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
-
- /* check if ME wants a reset */
- if (((dev->me_hw_state & ME_RDY_HRA) == 0)
- && (dev->heci_state != HECI_RESETING)
- && (dev->heci_state != HECI_INITIALIZING)) {
- DBG("FW not ready.\n");
- heci_reset(dev, 1);
- spin_unlock_bh(&dev->device_lock);
- return;
- }
-
- /* check if we need to start the dev */
- if ((dev->host_hw_state & H_RDY) == 0) {
- if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
- DBG("we need to start the dev.\n");
- dev->host_hw_state |= (H_IE | H_IG | H_RDY);
- heci_set_csr_register(dev);
- if (dev->heci_state == HECI_INITIALIZING) {
- dev->recvd_msg = 1;
- spin_unlock_bh(&dev->device_lock);
- wake_up_interruptible(&dev->wait_recvd_msg);
- return;
-
- } else {
- spin_unlock_bh(&dev->device_lock);
- tsk = kthread_run(heci_task_initialize_clients,
- dev, "heci_reinit");
- if (IS_ERR(tsk)) {
- int rc = PTR_ERR(tsk);
- printk(KERN_WARNING "heci: Unable to"
- "start the heci thread: %d\n", rc);
- }
- return;
- }
- } else {
- DBG("enable interrupt FW not ready.\n");
- heci_csr_enable_interrupts(dev);
- spin_unlock_bh(&dev->device_lock);
- return;
- }
- }
- /* check slots avalable for reading */
- slots = count_full_read_slots(dev);
- DBG("slots =%08x extra_write_index =%08x.\n",
- slots, dev->extra_write_index);
- while ((slots > 0) && (!dev->extra_write_index)) {
- DBG("slots =%08x extra_write_index =%08x.\n", slots,
- dev->extra_write_index);
- DBG("call heci_bh_read_handler.\n");
- rets = heci_bh_read_handler(&complete_list, dev, &slots);
- if (rets != 0)
- goto end;
- }
- rets = heci_bh_write_handler(&complete_list, dev, &slots);
-end:
- DBG("end of bottom half function.\n");
- dev->host_hw_state = read_heci_register(dev, H_CSR);
- dev->host_buffer_is_empty = host_buffer_is_empty(dev);
-
- if ((dev->host_hw_state & H_IS) == H_IS) {
- /* acknowledge interrupt and disable interrupts */
- heci_csr_disable_interrupts(dev);
-
- /* clear H_IS bit in H_CSR */
- heci_csr_clear_his(dev);
-
- PREPARE_WORK(&dev->work, heci_bh_handler);
- DBG("schedule work the heci_bh_handler.\n");
- rets = schedule_work(&dev->work);
- if (!rets)
- DBG("heci_bh_handler was already queued.\n");
- } else {
- heci_csr_enable_interrupts(dev);
- }
-
- if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
- DBG("received waiting bus message\n");
- bus_message_received = 1;
- }
- spin_unlock_bh(&dev->device_lock);
- if (bus_message_received) {
- DBG("wake up dev->wait_recvd_msg\n");
- wake_up_interruptible(&dev->wait_recvd_msg);
- bus_message_received = 0;
- }
- if ((complete_list.status != 0)
- || list_empty(&complete_list.heci_cb.cb_list))
- return;
-
-
- list_for_each_entry_safe(cb_pos, cb_next,
- &complete_list.heci_cb.cb_list, cb_list) {
- file_ext = (struct heci_file_private *)cb_pos->file_private;
- list_del(&cb_pos->cb_list);
- if (file_ext != NULL) {
- if (file_ext != &dev->iamthif_file_ext) {
- DBG("completing call back.\n");
- _heci_cmpl(file_ext, cb_pos);
- cb_pos = NULL;
- } else if (file_ext == &dev->iamthif_file_ext) {
- _heci_cmpl_iamthif(dev, cb_pos);
- }
- }
- }
-}
-
-
-/**
- * heci_bh_read_handler - bottom half read routine after ISR to
- * handle the read processing.
- *
- * @cmpl_list: An instance of our list structure
- * @dev: Device object for our driver
- * @slots: slots to read.
- *
- * returns 0 on success, <0 on failure.
- */
-static int heci_bh_read_handler(struct io_heci_list *cmpl_list,
- struct iamt_heci_device *dev,
- __s32 *slots)
-{
- struct heci_msg_hdr *heci_hdr;
- int ret = 0;
- struct heci_file_private *file_pos = NULL;
- struct heci_file_private *file_next = NULL;
-
- if (!dev->rd_msg_hdr) {
- dev->rd_msg_hdr = read_heci_register(dev, ME_CB_RW);
- DBG("slots=%08x.\n", *slots);
- (*slots)--;
- DBG("slots=%08x.\n", *slots);
- }
- heci_hdr = (struct heci_msg_hdr *) &dev->rd_msg_hdr;
- DBG("heci_hdr->length =%d\n", heci_hdr->length);
-
- if ((heci_hdr->reserved) || !(dev->rd_msg_hdr)) {
- DBG("corrupted message header.\n");
- ret = -ECORRUPTED_MESSAGE_HEADER;
- goto end;
- }
-
- if ((heci_hdr->host_addr) || (heci_hdr->me_addr)) {
- list_for_each_entry_safe(file_pos, file_next,
- &dev->file_list, link) {
- DBG("list_for_each_entry_safe read host"
- " client = %d, ME client = %d\n",
- file_pos->host_client_id,
- file_pos->me_client_id);
- if ((file_pos->host_client_id == heci_hdr->host_addr)
- && (file_pos->me_client_id == heci_hdr->me_addr))
- break;
- }
-
- if (&file_pos->link == &dev->file_list) {
- DBG("corrupted message header\n");
- ret = -ECORRUPTED_MESSAGE_HEADER;
- goto end;
- }
- }
- if (((*slots) * sizeof(__u32)) < heci_hdr->length) {
- DBG("we can't read the message slots=%08x.\n", *slots);
- /* we can't read the message */
- ret = -ERANGE;
- goto end;
- }
-
- /* decide where to read the message too */
- if (!heci_hdr->host_addr) {
- DBG("call heci_bh_read_bus_message.\n");
- heci_bh_read_bus_message(dev, heci_hdr);
- DBG("end heci_bh_read_bus_message.\n");
- } else if ((heci_hdr->host_addr == dev->iamthif_file_ext.host_client_id)
- && (HECI_FILE_CONNECTED == dev->iamthif_file_ext.state)
- && (dev->iamthif_state == HECI_IAMTHIF_READING)) {
- DBG("call heci_bh_read_iamthif_message.\n");
- DBG("heci_hdr->length =%d\n", heci_hdr->length);
- ret = heci_bh_read_pthi_message(cmpl_list, dev, heci_hdr);
- if (ret != 0)
- goto end;
-
- } else {
- DBG("call heci_bh_read_client_message.\n");
- ret = heci_bh_read_client_message(cmpl_list, dev, heci_hdr);
- if (ret != 0)
- goto end;
-
- }
-
- /* reset the number of slots and header */
- *slots = count_full_read_slots(dev);
- dev->rd_msg_hdr = 0;
-
- if (*slots == -ESLOTS_OVERFLOW) {
- /* overflow - reset */
- DBG("reseting due to slots overflow.\n");
- /* set the event since message has been read */
- ret = -ERANGE;
- goto end;
- }
-end:
- return ret;
-}
-
-
-/**
- * heci_bh_read_bus_message - bottom half read routine after ISR to
- * handle the read bus message cmd processing.
- *
- * @dev: Device object for our driver
- * @heci_hdr: header of bus message
- */
-static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
- struct heci_msg_hdr *heci_hdr)
-{
- struct heci_bus_message *heci_msg;
- struct hbm_host_version_response *version_res;
- struct hbm_client_connect_response *connect_res;
- struct hbm_client_connect_response *disconnect_res;
- struct hbm_flow_control *flow_control;
- struct hbm_props_response *props_res;
- struct hbm_host_enum_response *enum_res;
- struct hbm_client_disconnect_request *disconnect_req;
- struct hbm_host_stop_request *h_stop_req;
- int i;
- unsigned char *buffer;
-
- /* read the message to our buffer */
- buffer = (unsigned char *) dev->rd_msg_buf;
- BUG_ON(heci_hdr->length >= sizeof(dev->rd_msg_buf));
- heci_read_slots(dev, buffer, heci_hdr->length);
- heci_msg = (struct heci_bus_message *) buffer;
-
- switch (*(__u8 *) heci_msg) {
- case HOST_START_RES_CMD:
- version_res = (struct hbm_host_version_response *) heci_msg;
- if (version_res->host_version_supported) {
- dev->version.major_version = HBM_MAJOR_VERSION;
- dev->version.minor_version = HBM_MINOR_VERSION;
- } else {
- dev->version = version_res->me_max_version;
- }
- dev->recvd_msg = 1;
- DBG("host start response message received.\n");
- break;
-
- case CLIENT_CONNECT_RES_CMD:
- connect_res =
- (struct hbm_client_connect_response *) heci_msg;
- heci_client_connect_response(dev, connect_res);
- DBG("client connect response message received.\n");
- wake_up(&dev->wait_recvd_msg);
- break;
-
- case CLIENT_DISCONNECT_RES_CMD:
- disconnect_res =
- (struct hbm_client_connect_response *) heci_msg;
- heci_client_disconnect_response(dev, disconnect_res);
- DBG("client disconnect response message received.\n");
- wake_up(&dev->wait_recvd_msg);
- break;
-
- case HECI_FLOW_CONTROL_CMD:
- flow_control = (struct hbm_flow_control *) heci_msg;
- heci_client_flow_control_response(dev, flow_control);
- DBG("client flow control response message received.\n");
- break;
-
- case HOST_CLIENT_PROPERTEIS_RES_CMD:
- props_res = (struct hbm_props_response *) heci_msg;
- if (props_res->status != 0) {
- BUG();
- break;
- }
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (dev->me_clients[i].client_id ==
- props_res->address) {
- dev->me_clients[i].props =
- props_res->client_properties;
- break;
- }
-
- }
- dev->recvd_msg = 1;
- break;
-
- case HOST_ENUM_RES_CMD:
- enum_res = (struct hbm_host_enum_response *) heci_msg;
- memcpy(dev->heci_me_clients, enum_res->valid_addresses, 32);
- dev->recvd_msg = 1;
- break;
-
- case HOST_STOP_RES_CMD:
- dev->heci_state = HECI_DISABLED;
- DBG("reseting because of FW stop response.\n");
- heci_reset(dev, 1);
- break;
-
- case CLIENT_DISCONNECT_REQ_CMD:
- /* search for client */
- disconnect_req =
- (struct hbm_client_disconnect_request *) heci_msg;
- heci_client_disconnect_request(dev, disconnect_req);
- break;
-
- case ME_STOP_REQ_CMD:
- /* prepare stop request */
- heci_hdr = (struct heci_msg_hdr *) &dev->ext_msg_buf[0];
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length = sizeof(struct hbm_host_stop_request);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
- h_stop_req =
- (struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
- memset(h_stop_req, 0, sizeof(struct hbm_host_stop_request));
- h_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
- h_stop_req->reason = DRIVER_STOP_REQUEST;
- h_stop_req->reserved[0] = 0;
- h_stop_req->reserved[1] = 0;
- dev->extra_write_index = 2;
- break;
-
- default:
- BUG();
- break;
-
- }
-}
-
-/**
- * heci_bh_read_pthi_message - bottom half read routine after ISR to
- * handle the read pthi message data processing.
- *
- * @complete_list: An instance of our list structure
- * @dev: Device object for our driver
- * @heci_hdr: header of pthi message
- *
- * returns 0 on success, <0 on failure.
- */
-static int heci_bh_read_pthi_message(struct io_heci_list *complete_list,
- struct iamt_heci_device *dev,
- struct heci_msg_hdr *heci_hdr)
-{
- struct heci_file_private *file_ext;
- struct heci_cb_private *priv_cb;
- unsigned char *buffer;
-
- BUG_ON(heci_hdr->me_addr != dev->iamthif_file_ext.me_client_id);
- BUG_ON(dev->iamthif_state != HECI_IAMTHIF_READING);
-
- buffer = (unsigned char *) (dev->iamthif_msg_buf +
- dev->iamthif_msg_buf_index);
- BUG_ON(sizeof(dev->iamthif_msg_buf) <
- (dev->iamthif_msg_buf_index + heci_hdr->length));
-
- heci_read_slots(dev, buffer, heci_hdr->length);
-
- dev->iamthif_msg_buf_index += heci_hdr->length;
-
- if (!(heci_hdr->msg_complete))
- return 0;
-
- DBG("pthi_message_buffer_index=%d\n", heci_hdr->length);
- DBG("completed pthi read.\n ");
- if (!dev->iamthif_current_cb)
- return -ENODEV;
-
- priv_cb = dev->iamthif_current_cb;
- dev->iamthif_current_cb = NULL;
-
- file_ext = (struct heci_file_private *)priv_cb->file_private;
- if (!file_ext)
- return -ENODEV;
-
- dev->iamthif_stall_timer = 0;
- priv_cb->information = dev->iamthif_msg_buf_index;
- priv_cb->read_time = get_seconds();
- if ((dev->iamthif_ioctl) && (file_ext == &dev->iamthif_file_ext)) {
- /* found the iamthif cb */
- DBG("complete the pthi read cb.\n ");
- if (&dev->iamthif_file_ext) {
- DBG("add the pthi read cb to complete.\n ");
- list_add_tail(&priv_cb->cb_list,
- &complete_list->heci_cb.cb_list);
- }
- }
- return 0;
-}
-
-/**
- * _heci_bh_state_ok - check if heci header matches file private data
- *
- * @file_ext: private data of the file object
- * @heci_hdr: header of heci client message
- *
- * returns !=0 if matches, 0 if no match.
- */
-static int _heci_bh_state_ok(struct heci_file_private *file_ext,
- struct heci_msg_hdr *heci_hdr)
-{
- return ((file_ext->host_client_id == heci_hdr->host_addr)
- && (file_ext->me_client_id == heci_hdr->me_addr)
- && (file_ext->state == HECI_FILE_CONNECTED)
- && (HECI_READ_COMPLETE != file_ext->reading_state));
-}
-
-/**
- * heci_bh_read_client_message - bottom half read routine after ISR to
- * handle the read heci client message data processing.
- *
- * @complete_list: An instance of our list structure
- * @dev: Device object for our driver
- * @heci_hdr: header of heci client message
- *
- * returns 0 on success, <0 on failure.
- */
-static int heci_bh_read_client_message(struct io_heci_list *complete_list,
- struct iamt_heci_device *dev,
- struct heci_msg_hdr *heci_hdr)
-{
- struct heci_file_private *file_ext;
- struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
- unsigned char *buffer = NULL;
-
- DBG("start client msg\n");
- if (!((dev->read_list.status == 0) &&
- !list_empty(&dev->read_list.heci_cb.cb_list)))
- goto quit;
-
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &dev->read_list.heci_cb.cb_list, cb_list) {
- file_ext = (struct heci_file_private *)
- priv_cb_pos->file_private;
- if ((file_ext != NULL) &&
- (_heci_bh_state_ok(file_ext, heci_hdr))) {
- spin_lock_bh(&file_ext->read_io_lock);
- file_ext->reading_state = HECI_READING;
- buffer = (unsigned char *)
- (priv_cb_pos->response_buffer.data +
- priv_cb_pos->information);
- BUG_ON(priv_cb_pos->response_buffer.size <
- heci_hdr->length +
- priv_cb_pos->information);
-
- if (priv_cb_pos->response_buffer.size <
- heci_hdr->length +
- priv_cb_pos->information) {
- DBG("message overflow.\n");
- list_del(&priv_cb_pos->cb_list);
- spin_unlock_bh(&file_ext->read_io_lock);
- return -ENOMEM;
- }
- if (buffer) {
- heci_read_slots(dev, buffer,
- heci_hdr->length);
- }
- priv_cb_pos->information += heci_hdr->length;
- if (heci_hdr->msg_complete) {
- file_ext->status = 0;
- list_del(&priv_cb_pos->cb_list);
- spin_unlock_bh(&file_ext->read_io_lock);
- DBG("completed read host client = %d,"
- "ME client = %d, "
- "data length = %lu\n",
- file_ext->host_client_id,
- file_ext->me_client_id,
- priv_cb_pos->information);
-
- *(priv_cb_pos->response_buffer.data +
- priv_cb_pos->information) = '\0';
- DBG("priv_cb_pos->res_buffer - %s\n",
- priv_cb_pos->response_buffer.data);
- list_add_tail(&priv_cb_pos->cb_list,
- &complete_list->heci_cb.cb_list);
- } else {
- spin_unlock_bh(&file_ext->read_io_lock);
- }
-
- break;
- }
-
- }
-
-quit:
- DBG("message read\n");
- if (!buffer) {
- heci_read_slots(dev, (unsigned char *) dev->rd_msg_buf,
- heci_hdr->length);
- DBG("discarding message, header=%08x.\n",
- *(__u32 *) dev->rd_msg_buf);
- }
-
- return 0;
-}
-
-/**
- * _heci_bh_iamthif_read - prepare to read iamthif data.
- *
- * @dev: Device object for our driver.
- * @slots: free slots.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _heci_bh_iamthif_read(struct iamt_heci_device *dev, __s32 *slots)
-{
-
- if (((*slots) * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr)
- + sizeof(struct hbm_flow_control))) {
- *slots -= (sizeof(struct heci_msg_hdr) +
- sizeof(struct hbm_flow_control) + 3) / 4;
- if (!heci_send_flow_control(dev, &dev->iamthif_file_ext)) {
- DBG("iamthif flow control failed\n");
- } else {
- DBG("iamthif flow control success\n");
- dev->iamthif_state = HECI_IAMTHIF_READING;
- dev->iamthif_flow_control_pending = 0;
- dev->iamthif_msg_buf_index = 0;
- dev->iamthif_msg_buf_size = 0;
- dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
- dev->host_buffer_is_empty = host_buffer_is_empty(dev);
- }
- return 0;
- } else {
- return -ECOMPLETE_MESSAGE;
- }
-}
-
-/**
- * _heci_bh_close - process close related operation.
- *
- * @dev: Device object for our driver.
- * @slots: free slots.
- * @priv_cb_pos: callback block.
- * @file_ext: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _heci_bh_close(struct iamt_heci_device *dev, __s32 *slots,
- struct heci_cb_private *priv_cb_pos,
- struct heci_file_private *file_ext,
- struct io_heci_list *cmpl_list)
-{
- if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
- sizeof(struct hbm_client_disconnect_request))) {
- *slots -= (sizeof(struct heci_msg_hdr) +
- sizeof(struct hbm_client_disconnect_request) + 3) / 4;
-
- if (!heci_disconnect(dev, file_ext)) {
- file_ext->status = 0;
- priv_cb_pos->information = 0;
- list_move_tail(&priv_cb_pos->cb_list,
- &cmpl_list->heci_cb.cb_list);
- return -ECOMPLETE_MESSAGE;
- } else {
- file_ext->state = HECI_FILE_DISCONNECTING;
- file_ext->status = 0;
- priv_cb_pos->information = 0;
- list_move_tail(&priv_cb_pos->cb_list,
- &dev->ctrl_rd_list.heci_cb.cb_list);
- file_ext->timer_count = HECI_CONNECT_TIMEOUT;
- }
- } else {
- /* return the cancel routine */
- return -ECORRUPTED_MESSAGE_HEADER;
- }
-
- return 0;
-}
-
-/**
- * _heci_hb_close - process read related operation.
- *
- * @dev: Device object for our driver.
- * @slots: free slots.
- * @priv_cb_pos: callback block.
- * @file_ext: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _heci_bh_read(struct iamt_heci_device *dev, __s32 *slots,
- struct heci_cb_private *priv_cb_pos,
- struct heci_file_private *file_ext,
- struct io_heci_list *cmpl_list)
-{
- if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
- sizeof(struct hbm_flow_control))) {
- *slots -= (sizeof(struct heci_msg_hdr) +
- sizeof(struct hbm_flow_control) + 3) / 4;
- if (!heci_send_flow_control(dev, file_ext)) {
- file_ext->status = -ENODEV;
- priv_cb_pos->information = 0;
- list_move_tail(&priv_cb_pos->cb_list,
- &cmpl_list->heci_cb.cb_list);
- return -ENODEV;
- } else {
- list_move_tail(&priv_cb_pos->cb_list,
- &dev->read_list.heci_cb.cb_list);
- }
- } else {
- /* return the cancel routine */
- list_del(&priv_cb_pos->cb_list);
- return -ECORRUPTED_MESSAGE_HEADER;
- }
-
- return 0;
-}
-
-
-/**
- * _heci_bh_ioctl - process ioctl related operation.
- *
- * @dev: Device object for our driver.
- * @slots: free slots.
- * @priv_cb_pos: callback block.
- * @file_ext: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _heci_bh_ioctl(struct iamt_heci_device *dev, __s32 *slots,
- struct heci_cb_private *priv_cb_pos,
- struct heci_file_private *file_ext,
- struct io_heci_list *cmpl_list)
-{
- if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
- sizeof(struct hbm_client_connect_request))) {
- file_ext->state = HECI_FILE_CONNECTING;
- *slots -= (sizeof(struct heci_msg_hdr) +
- sizeof(struct hbm_client_connect_request) + 3) / 4;
- if (!heci_connect(dev, file_ext)) {
- file_ext->status = -ENODEV;
- priv_cb_pos->information = 0;
- list_del(&priv_cb_pos->cb_list);
- return -ENODEV;
- } else {
- list_move_tail(&priv_cb_pos->cb_list,
- &dev->ctrl_rd_list.heci_cb.cb_list);
- file_ext->timer_count = HECI_CONNECT_TIMEOUT;
- }
- } else {
- /* return the cancel routine */
- list_del(&priv_cb_pos->cb_list);
- return -ECORRUPTED_MESSAGE_HEADER;
- }
-
- return 0;
-}
-
-/**
- * _heci_bh_cmpl - process completed and no-iamthif operation.
- *
- * @dev: Device object for our driver.
- * @slots: free slots.
- * @priv_cb_pos: callback block.
- * @file_ext: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _heci_bh_cmpl(struct iamt_heci_device *dev, __s32 *slots,
- struct heci_cb_private *priv_cb_pos,
- struct heci_file_private *file_ext,
- struct io_heci_list *cmpl_list)
-{
- struct heci_msg_hdr *heci_hdr;
-
- if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
- (priv_cb_pos->request_buffer.size -
- priv_cb_pos->information))) {
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = file_ext->host_client_id;
- heci_hdr->me_addr = file_ext->me_client_id;
- heci_hdr->length = ((priv_cb_pos->request_buffer.size) -
- (priv_cb_pos->information));
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
- DBG("priv_cb_pos->request_buffer.size =%d"
- "heci_hdr->msg_complete= %d\n",
- priv_cb_pos->request_buffer.size,
- heci_hdr->msg_complete);
- DBG("priv_cb_pos->information =%lu\n",
- priv_cb_pos->information);
- DBG("heci_hdr->length =%d\n",
- heci_hdr->length);
- *slots -= (sizeof(struct heci_msg_hdr) +
- heci_hdr->length + 3) / 4;
- if (!heci_write_message(dev, heci_hdr,
- (unsigned char *)
- (priv_cb_pos->request_buffer.data +
- priv_cb_pos->information),
- heci_hdr->length)) {
- file_ext->status = -ENODEV;
- list_move_tail(&priv_cb_pos->cb_list,
- &cmpl_list->heci_cb.cb_list);
- return -ENODEV;
- } else {
- flow_ctrl_reduce(dev, file_ext);
- file_ext->status = 0;
- priv_cb_pos->information += heci_hdr->length;
- list_move_tail(&priv_cb_pos->cb_list,
- &dev->write_waiting_list.heci_cb.cb_list);
- }
- } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
- /* buffer is still empty */
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = file_ext->host_client_id;
- heci_hdr->me_addr = file_ext->me_client_id;
- heci_hdr->length =
- (*slots * sizeof(__u32)) - sizeof(struct heci_msg_hdr);
- heci_hdr->msg_complete = 0;
- heci_hdr->reserved = 0;
-
- (*slots) -= (sizeof(struct heci_msg_hdr) +
- heci_hdr->length + 3) / 4;
- if (!heci_write_message(dev, heci_hdr,
- (unsigned char *)
- (priv_cb_pos->request_buffer.data +
- priv_cb_pos->information),
- heci_hdr->length)) {
- file_ext->status = -ENODEV;
- list_move_tail(&priv_cb_pos->cb_list,
- &cmpl_list->heci_cb.cb_list);
- return -ENODEV;
- } else {
- priv_cb_pos->information += heci_hdr->length;
- DBG("priv_cb_pos->request_buffer.size =%d"
- " heci_hdr->msg_complete= %d\n",
- priv_cb_pos->request_buffer.size,
- heci_hdr->msg_complete);
- DBG("priv_cb_pos->information =%lu\n",
- priv_cb_pos->information);
- DBG("heci_hdr->length =%d\n", heci_hdr->length);
- }
- return -ECOMPLETE_MESSAGE;
- } else {
- return -ECORRUPTED_MESSAGE_HEADER;
- }
-
- return 0;
-}
-
-/**
- * _heci_bh_cmpl_iamthif - process completed iamthif operation.
- *
- * @dev: Device object for our driver.
- * @slots: free slots.
- * @priv_cb_pos: callback block.
- * @file_ext: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _heci_bh_cmpl_iamthif(struct iamt_heci_device *dev, __s32 *slots,
- struct heci_cb_private *priv_cb_pos,
- struct heci_file_private *file_ext,
- struct io_heci_list *cmpl_list)
-{
- struct heci_msg_hdr *heci_hdr;
-
- if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
- dev->iamthif_msg_buf_size -
- dev->iamthif_msg_buf_index)) {
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = file_ext->host_client_id;
- heci_hdr->me_addr = file_ext->me_client_id;
- heci_hdr->length = dev->iamthif_msg_buf_size -
- dev->iamthif_msg_buf_index;
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- *slots -= (sizeof(struct heci_msg_hdr) +
- heci_hdr->length + 3) / 4;
-
- if (!heci_write_message(dev, heci_hdr,
- (dev->iamthif_msg_buf +
- dev->iamthif_msg_buf_index),
- heci_hdr->length)) {
- dev->iamthif_state = HECI_IAMTHIF_IDLE;
- file_ext->status = -ENODEV;
- list_del(&priv_cb_pos->cb_list);
- return -ENODEV;
- } else {
- flow_ctrl_reduce(dev, file_ext);
- dev->iamthif_msg_buf_index += heci_hdr->length;
- priv_cb_pos->information = dev->iamthif_msg_buf_index;
- file_ext->status = 0;
- dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL;
- dev->iamthif_flow_control_pending = 1;
- /* save iamthif cb sent to pthi client */
- dev->iamthif_current_cb = priv_cb_pos;
- list_move_tail(&priv_cb_pos->cb_list,
- &dev->write_waiting_list.heci_cb.cb_list);
-
- }
- } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
- /* buffer is still empty */
- heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
- heci_hdr->host_addr = file_ext->host_client_id;
- heci_hdr->me_addr = file_ext->me_client_id;
- heci_hdr->length =
- (*slots * sizeof(__u32)) - sizeof(struct heci_msg_hdr);
- heci_hdr->msg_complete = 0;
- heci_hdr->reserved = 0;
-
- *slots -= (sizeof(struct heci_msg_hdr) +
- heci_hdr->length + 3) / 4;
-
- if (!heci_write_message(dev, heci_hdr,
- (dev->iamthif_msg_buf +
- dev->iamthif_msg_buf_index),
- heci_hdr->length)) {
- file_ext->status = -ENODEV;
- list_del(&priv_cb_pos->cb_list);
- } else {
- dev->iamthif_msg_buf_index += heci_hdr->length;
- }
- return -ECOMPLETE_MESSAGE;
- } else {
- return -ECORRUPTED_MESSAGE_HEADER;
- }
-
- return 0;
-}
-
-/**
- * heci_bh_write_handler - bottom half write routine after
- * ISR to handle the write processing.
- *
- * @cmpl_list: An instance of our list structure
- * @dev: Device object for our driver
- * @slots: slots to write.
- *
- * returns 0 on success, <0 on failure.
- */
-static int heci_bh_write_handler(struct io_heci_list *cmpl_list,
- struct iamt_heci_device *dev,
- __s32 *slots)
-{
-
- struct heci_file_private *file_ext;
- struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
- struct io_heci_list *list;
- int ret;
-
- if (!host_buffer_is_empty(dev)) {
- DBG("host buffer is not empty.\n");
- return 0;
- }
- dev->write_hang = -1;
- *slots = count_empty_write_slots(dev);
- /* complete all waiting for write CB */
- DBG("complete all waiting for write cb.\n");
-
- list = &dev->write_waiting_list;
- if ((list->status == 0)
- && !list_empty(&list->heci_cb.cb_list)) {
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &list->heci_cb.cb_list, cb_list) {
- file_ext = (struct heci_file_private *)
- priv_cb_pos->file_private;
- if (file_ext != NULL) {
- file_ext->status = 0;
- list_del(&priv_cb_pos->cb_list);
- if ((HECI_WRITING == file_ext->writing_state) &&
- (priv_cb_pos->major_file_operations ==
- HECI_WRITE) &&
- (file_ext != &dev->iamthif_file_ext)) {
- DBG("HECI WRITE COMPLETE\n");
- file_ext->writing_state =
- HECI_WRITE_COMPLETE;
- list_add_tail(&priv_cb_pos->cb_list,
- &cmpl_list->heci_cb.cb_list);
- }
- if (file_ext == &dev->iamthif_file_ext) {
- DBG("check iamthif flow control.\n");
- if (dev->iamthif_flow_control_pending) {
- ret = _heci_bh_iamthif_read(dev,
- slots);
- if (ret != 0)
- return ret;
- }
- }
- }
-
- }
- }
-
- if ((dev->stop) && (!dev->wd_pending)) {
- dev->wd_stoped = 1;
- wake_up_interruptible(&dev->wait_stop_wd);
- return 0;
- }
-
- if (dev->extra_write_index != 0) {
- DBG("extra_write_index =%d.\n", dev->extra_write_index);
- heci_write_message(dev,
- (struct heci_msg_hdr *) &dev->ext_msg_buf[0],
- (unsigned char *) &dev->ext_msg_buf[1],
- (dev->extra_write_index - 1) * sizeof(__u32));
- *slots -= dev->extra_write_index;
- dev->extra_write_index = 0;
- }
- if (dev->heci_state == HECI_ENABLED) {
- if ((dev->wd_pending)
- && flow_ctrl_creds(dev, &dev->wd_file_ext)) {
- if (!heci_send_wd(dev))
- DBG("wd send failed.\n");
- else
- flow_ctrl_reduce(dev, &dev->wd_file_ext);
-
- dev->wd_pending = 0;
-
- if (dev->wd_timeout != 0) {
- *slots -= (sizeof(struct heci_msg_hdr) +
- HECI_START_WD_DATA_SIZE + 3) / 4;
- dev->wd_due_counter = 2;
- } else {
- *slots -= (sizeof(struct heci_msg_hdr) +
- HECI_WD_PARAMS_SIZE + 3) / 4;
- dev->wd_due_counter = 0;
- }
-
- }
- }
- if (dev->stop)
- return ~ENODEV;
-
- /* complete control write list CB */
- if (dev->ctrl_wr_list.status == 0) {
- /* complete control write list CB */
- DBG("complete control write list cb.\n");
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &dev->ctrl_wr_list.heci_cb.cb_list, cb_list) {
- file_ext = (struct heci_file_private *)
- priv_cb_pos->file_private;
- if (file_ext == NULL) {
- list_del(&priv_cb_pos->cb_list);
- return -ENODEV;
- }
- switch (priv_cb_pos->major_file_operations) {
- case HECI_CLOSE:
- /* send disconnect message */
- ret = _heci_bh_close(dev, slots,
- priv_cb_pos,
- file_ext, cmpl_list);
- if (ret != 0)
- return ret;
-
- break;
- case HECI_READ:
- /* send flow control message */
- ret = _heci_bh_read(dev, slots,
- priv_cb_pos,
- file_ext, cmpl_list);
- if (ret != 0)
- return ret;
-
- break;
- case HECI_IOCTL:
- /* connect message */
- if (!other_client_is_connecting(dev, file_ext))
- continue;
- ret = _heci_bh_ioctl(dev, slots,
- priv_cb_pos,
- file_ext, cmpl_list);
- if (ret != 0)
- return ret;
-
- break;
-
- default:
- BUG();
- }
-
- }
- }
- /* complete write list CB */
- if ((dev->write_list.status == 0)
- && !list_empty(&dev->write_list.heci_cb.cb_list)) {
- DBG("complete write list cb.\n");
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &dev->write_list.heci_cb.cb_list, cb_list) {
- file_ext = (struct heci_file_private *)
- priv_cb_pos->file_private;
-
- if (file_ext != NULL) {
- if (file_ext != &dev->iamthif_file_ext) {
- if (!flow_ctrl_creds(dev, file_ext)) {
- DBG("No flow control"
- " credentials for client"
- " %d, not sending.\n",
- file_ext->host_client_id);
- continue;
- }
- ret = _heci_bh_cmpl(dev, slots,
- priv_cb_pos,
- file_ext,
- cmpl_list);
- if (ret != 0)
- return ret;
-
- } else if (file_ext == &dev->iamthif_file_ext) {
- /* IAMTHIF IOCTL */
- DBG("complete pthi write cb.\n");
- if (!flow_ctrl_creds(dev, file_ext)) {
- DBG("No flow control"
- " credentials for pthi"
- " client %d.\n",
- file_ext->host_client_id);
- continue;
- }
- ret = _heci_bh_cmpl_iamthif(dev, slots,
- priv_cb_pos,
- file_ext,
- cmpl_list);
- if (ret != 0)
- return ret;
-
- }
- }
-
- }
- }
- return 0;
-}
-
-
-/**
- * is_treat_specially_client - check if the message belong
- * to the file private data.
- *
- * @file_ext: private data of the file object
- * @rs: connect response bus message
- * @dev: Device object for our driver
- *
- * returns 0 on success, <0 on failure.
- */
-static int is_treat_specially_client(struct heci_file_private *file_ext,
- struct hbm_client_connect_response *rs)
-{
- int ret = 0;
-
- if ((file_ext->host_client_id == rs->host_addr) &&
- (file_ext->me_client_id == rs->me_addr)) {
- if (rs->status == 0) {
- DBG("client connect status = 0x%08x.\n", rs->status);
- file_ext->state = HECI_FILE_CONNECTED;
- file_ext->status = 0;
- } else {
- DBG("client connect status = 0x%08x.\n", rs->status);
- file_ext->state = HECI_FILE_DISCONNECTED;
- file_ext->status = -ENODEV;
- }
- ret = 1;
- }
- DBG("client state = %d.\n", file_ext->state);
- return ret;
-}
-
-/**
- * heci_client_connect_response - connect response bh routine
- *
- * @dev: Device object for our driver
- * @rs: connect response bus message
- */
-static void heci_client_connect_response(struct iamt_heci_device *dev,
- struct hbm_client_connect_response *rs)
-{
-
- struct heci_file_private *file_ext;
- struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
-
- /* if WD or iamthif client treat specially */
-
- if ((is_treat_specially_client(&(dev->wd_file_ext), rs)) ||
- (is_treat_specially_client(&(dev->iamthif_file_ext), rs)))
- return;
-
- if (dev->ctrl_rd_list.status == 0
- && !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) {
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &dev->ctrl_rd_list.heci_cb.cb_list, cb_list) {
- file_ext = (struct heci_file_private *)
- priv_cb_pos->file_private;
- if (file_ext == NULL) {
- list_del(&priv_cb_pos->cb_list);
- return;
- }
- if (HECI_IOCTL == priv_cb_pos->major_file_operations) {
- if (is_treat_specially_client(file_ext, rs)) {
- list_del(&priv_cb_pos->cb_list);
- file_ext->status = 0;
- file_ext->timer_count = 0;
- break;
- }
- }
- }
- }
-}
-
-/**
- * heci_client_disconnect_response - disconnect response bh routine
- *
- * @dev: Device object for our driver
- * @rs: disconnect response bus message
- */
-static void heci_client_disconnect_response(struct iamt_heci_device *dev,
- struct hbm_client_connect_response *rs)
-{
- struct heci_file_private *file_ext;
- struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
-
- if (dev->ctrl_rd_list.status == 0
- && !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) {
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &dev->ctrl_rd_list.heci_cb.cb_list, cb_list) {
- file_ext = (struct heci_file_private *)
- priv_cb_pos->file_private;
-
- if (file_ext == NULL) {
- list_del(&priv_cb_pos->cb_list);
- return;
- }
-
- DBG("list_for_each_entry_safe in ctrl_rd_list.\n");
- if ((file_ext->host_client_id == rs->host_addr) &&
- (file_ext->me_client_id == rs->me_addr)) {
-
- list_del(&priv_cb_pos->cb_list);
- if (rs->status == 0) {
- file_ext->state =
- HECI_FILE_DISCONNECTED;
- }
-
- file_ext->status = 0;
- file_ext->timer_count = 0;
- break;
- }
- }
- }
-}
-
-/**
- * same_flow_addr - tell they have same address.
- *
- * @file: private data of the file object.
- * @flow: flow control.
- *
- * returns !=0, same; 0,not.
- */
-static int same_flow_addr(struct heci_file_private *file,
- struct hbm_flow_control *flow)
-{
- return ((file->host_client_id == flow->host_addr)
- && (file->me_client_id == flow->me_addr));
-}
-
-/**
- * add_single_flow_creds - add single buffer credentials.
- *
- * @file: private data ot the file object.
- * @flow: flow control.
- */
-static void add_single_flow_creds(struct iamt_heci_device *dev,
- struct hbm_flow_control *flow)
-{
- struct heci_me_client *client;
- int i;
-
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- client = &dev->me_clients[i];
- if ((client != NULL) &&
- (flow->me_addr == client->client_id)) {
- if (client->props.single_recv_buf != 0) {
- client->flow_ctrl_creds++;
- DBG("recv flow ctrl msg ME %d (single).\n",
- flow->me_addr);
- DBG("flow control credentials=%d.\n",
- client->flow_ctrl_creds);
- } else {
- BUG(); /* error in flow control */
- }
- }
- }
-}
-
-/**
- * heci_client_flow_control_response - flow control response bh routine
- *
- * @dev: Device object for our driver
- * @flow_control: flow control response bus message
- */
-static void heci_client_flow_control_response(struct iamt_heci_device *dev,
- struct hbm_flow_control *flow_control)
-{
- struct heci_file_private *file_pos = NULL;
- struct heci_file_private *file_next = NULL;
-
- if (flow_control->host_addr == 0) {
- /* single receive buffer */
- add_single_flow_creds(dev, flow_control);
- } else {
- /* normal connection */
- list_for_each_entry_safe(file_pos, file_next,
- &dev->file_list, link) {
- DBG("list_for_each_entry_safe in file_list\n");
-
- DBG("file_ext of host client %d ME client %d.\n",
- file_pos->host_client_id,
- file_pos->me_client_id);
- DBG("flow ctrl msg for host %d ME %d.\n",
- flow_control->host_addr,
- flow_control->me_addr);
- if (same_flow_addr(file_pos, flow_control)) {
- DBG("recv ctrl msg for host %d ME %d.\n",
- flow_control->host_addr,
- flow_control->me_addr);
- file_pos->flow_ctrl_creds++;
- DBG("flow control credentials=%d.\n",
- file_pos->flow_ctrl_creds);
- break;
- }
- }
- }
-}
-
-/**
- * same_disconn_addr - tell they have same address
- *
- * @file: private data of the file object.
- * @disconn: disconnection request.
- *
- * returns !=0, same; 0,not.
- */
-static int same_disconn_addr(struct heci_file_private *file,
- struct hbm_client_disconnect_request *disconn)
-{
- return ((file->host_client_id == disconn->host_addr)
- && (file->me_client_id == disconn->me_addr));
-}
-
-/**
- * heci_client_disconnect_request - disconnect request bh routine
- *
- * @dev: Device object for our driver.
- * @disconnect_req: disconnect request bus message.
- */
-static void heci_client_disconnect_request(struct iamt_heci_device *dev,
- struct hbm_client_disconnect_request *disconnect_req)
-{
- struct heci_msg_hdr *heci_hdr;
- struct hbm_client_connect_response *disconnect_res;
- struct heci_file_private *file_pos = NULL;
- struct heci_file_private *file_next = NULL;
-
- list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) {
- if (same_disconn_addr(file_pos, disconnect_req)) {
- DBG("disconnect request host client %d ME client %d.\n",
- disconnect_req->host_addr,
- disconnect_req->me_addr);
- file_pos->state = HECI_FILE_DISCONNECTED;
- file_pos->timer_count = 0;
- if (file_pos == &dev->wd_file_ext) {
- dev->wd_due_counter = 0;
- dev->wd_pending = 0;
- } else if (file_pos == &dev->iamthif_file_ext)
- dev->iamthif_timer = 0;
-
- /* prepare disconnect response */
- heci_hdr =
- (struct heci_msg_hdr *) &dev->ext_msg_buf[0];
- heci_hdr->host_addr = 0;
- heci_hdr->me_addr = 0;
- heci_hdr->length =
- sizeof(struct hbm_client_connect_response);
- heci_hdr->msg_complete = 1;
- heci_hdr->reserved = 0;
-
- disconnect_res =
- (struct hbm_client_connect_response *)
- &dev->ext_msg_buf[1];
- disconnect_res->host_addr = file_pos->host_client_id;
- disconnect_res->me_addr = file_pos->me_client_id;
- *(__u8 *) (&disconnect_res->cmd) =
- CLIENT_DISCONNECT_RES_CMD;
- disconnect_res->status = 0;
- dev->extra_write_index = 2;
- break;
- }
- }
-}
-
-/**
- * heci_timer - timer function.
- *
- * @data: pointer to the device structure
- *
- * NOTE: This function is called by timer interrupt work
- */
-void heci_wd_timer(unsigned long data)
-{
- struct iamt_heci_device *dev = (struct iamt_heci_device *) data;
-
- DBG("send watchdog.\n");
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state != HECI_ENABLED) {
- mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
- spin_unlock_bh(&dev->device_lock);
- return;
- }
- if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) {
- mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
- spin_unlock_bh(&dev->device_lock);
- return;
- }
- /* Watchdog */
- if ((dev->wd_due_counter != 0) && (dev->wd_bypass == 0)) {
- if (--dev->wd_due_counter == 0) {
- if (dev->host_buffer_is_empty &&
- flow_ctrl_creds(dev, &dev->wd_file_ext)) {
- dev->host_buffer_is_empty = 0;
- if (!heci_send_wd(dev)) {
- DBG("wd send failed.\n");
- } else {
- flow_ctrl_reduce(dev,
- &dev->wd_file_ext);
- }
-
- if (dev->wd_timeout != 0)
- dev->wd_due_counter = 2;
- else
- dev->wd_due_counter = 0;
-
- } else
- dev->wd_pending = 1;
-
- }
- }
- if (dev->iamthif_stall_timer != 0) {
- if (--dev->iamthif_stall_timer == 0) {
- DBG("reseting because of hang to PTHI.\n");
- heci_reset(dev, 1);
- dev->iamthif_msg_buf_size = 0;
- dev->iamthif_msg_buf_index = 0;
- dev->iamthif_canceled = 0;
- dev->iamthif_ioctl = 1;
- dev->iamthif_state = HECI_IAMTHIF_IDLE;
- dev->iamthif_timer = 0;
- spin_unlock_bh(&dev->device_lock);
-
- if (dev->iamthif_current_cb)
- heci_free_cb_private(dev->iamthif_current_cb);
-
- spin_lock_bh(&dev->device_lock);
- dev->iamthif_file_object = NULL;
- dev->iamthif_current_cb = NULL;
- run_next_iamthif_cmd(dev);
- }
- }
- mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ));
- spin_unlock_bh(&dev->device_lock);
-}
+++ /dev/null
-/*
- * Part of Intel(R) Manageability Engine Interface Linux driver
- *
- * Copyright (c) 2003 - 2008 Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/aio.h>
-#include <linux/pci.h>
-#include <linux/reboot.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/ioctl.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/unistd.h>
-#include <linux/delay.h>
-
-#include "heci_data_structures.h"
-#include "heci.h"
-#include "heci_interface.h"
-#include "heci_version.h"
-
-
-/**
- * heci_ioctl_get_version - the get driver version IOCTL function
- *
- * @dev: Device object for our driver
- * @if_num: minor number
- * @*u_msg: pointer to user data struct in user space
- * @k_msg: data in kernel on the stack
- * @file_ext: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int heci_ioctl_get_version(struct iamt_heci_device *dev, int if_num,
- struct heci_message_data __user *u_msg,
- struct heci_message_data k_msg,
- struct heci_file_private *file_ext)
-{
- int rets = 0;
- struct heci_driver_version *version;
- struct heci_message_data res_msg;
-
- if ((if_num != HECI_MINOR_NUMBER) || (!dev)
- || (!file_ext))
- return -ENODEV;
-
- if (k_msg.size < (sizeof(struct heci_driver_version) - 2)) {
- DBG("user buffer less than heci_driver_version.\n");
- return -EMSGSIZE;
- }
-
- res_msg.data = kmalloc(sizeof(struct heci_driver_version), GFP_KERNEL);
- if (!res_msg.data) {
- DBG("failed allocation response buffer size = %d.\n",
- (int) sizeof(struct heci_driver_version));
- return -ENOMEM;
- }
-
- version = (struct heci_driver_version *) res_msg.data;
- version->major = MAJOR_VERSION;
- version->minor = MINOR_VERSION;
- version->hotfix = QUICK_FIX_NUMBER;
- version->build = VER_BUILD;
- res_msg.size = sizeof(struct heci_driver_version);
- if (k_msg.size < sizeof(struct heci_driver_version))
- res_msg.size -= 2;
-
- rets = file_ext->status;
- /* now copy the data to user space */
- if (copy_to_user((void __user *)k_msg.data, res_msg.data, res_msg.size)) {
- rets = -EFAULT;
- goto end;
- }
- if (put_user(res_msg.size, &u_msg->size)) {
- rets = -EFAULT;
- goto end;
- }
-end:
- kfree(res_msg.data);
- return rets;
-}
-
-/**
- * heci_ioctl_connect_client - the connect to fw client IOCTL function
- *
- * @dev: Device object for our driver
- * @if_num: minor number
- * @*u_msg: pointer to user data struct in user space
- * @k_msg: data in kernel on the stack
- * @file_ext: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num,
- struct heci_message_data __user *u_msg,
- struct heci_message_data k_msg,
- struct file *file)
-{
- int rets = 0;
- struct heci_message_data req_msg, res_msg;
- struct heci_cb_private *priv_cb = NULL;
- struct heci_client *client;
- struct heci_file_private *file_ext;
- struct heci_file_private *file_pos = NULL;
- struct heci_file_private *file_next = NULL;
- long timeout = 15; /*15 second */
- __u8 i;
- int err = 0;
-
- if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file))
- return -ENODEV;
-
- file_ext = file->private_data;
- if (!file_ext)
- return -ENODEV;
-
- if (k_msg.size != sizeof(struct guid)) {
- DBG("user buffer size is not equal to size of struct "
- "guid(16).\n");
- return -EMSGSIZE;
- }
-
- if (!k_msg.data)
- return -EIO;
-
- req_msg.data = kmalloc(sizeof(struct guid), GFP_KERNEL);
- res_msg.data = kmalloc(sizeof(struct heci_client), GFP_KERNEL);
-
- if (!res_msg.data) {
- DBG("failed allocation response buffer size = %d.\n",
- (int) sizeof(struct heci_client));
- kfree(req_msg.data);
- return -ENOMEM;
- }
- if (!req_msg.data) {
- DBG("failed allocation request buffer size = %d.\n",
- (int) sizeof(struct guid));
- kfree(res_msg.data);
- return -ENOMEM;
- }
- req_msg.size = sizeof(struct guid);
- res_msg.size = sizeof(struct heci_client);
-
- /* copy the message to kernel space -
- * use a pointer already copied into kernel space
- */
- if (copy_from_user(req_msg.data, (void __user *)k_msg.data, k_msg.size)) {
- rets = -EFAULT;
- goto end;
- }
- /* buffered ioctl cb */
- priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
- if (!priv_cb) {
- rets = -ENOMEM;
- goto end;
- }
- INIT_LIST_HEAD(&priv_cb->cb_list);
- priv_cb->response_buffer.data = res_msg.data;
- priv_cb->response_buffer.size = res_msg.size;
- priv_cb->request_buffer.data = req_msg.data;
- priv_cb->request_buffer.size = req_msg.size;
- priv_cb->major_file_operations = HECI_IOCTL;
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state != HECI_ENABLED) {
- rets = -ENODEV;
- spin_unlock_bh(&dev->device_lock);
- goto end;
- }
- if ((file_ext->state != HECI_FILE_INITIALIZING) &&
- (file_ext->state != HECI_FILE_DISCONNECTED)) {
- rets = -EBUSY;
- spin_unlock_bh(&dev->device_lock);
- goto end;
- }
-
- /* find ME client we're trying to connect to */
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (memcmp((struct guid *)req_msg.data,
- &dev->me_clients[i].props.protocol_name,
- sizeof(struct guid)) == 0) {
- if (dev->me_clients[i].props.fixed_address == 0) {
- file_ext->me_client_id =
- dev->me_clients[i].client_id;
- file_ext->state = HECI_FILE_CONNECTING;
- }
- break;
- }
- }
- /* if we're connecting to PTHI client so we will use the exist
- * connection
- */
- if (memcmp((struct guid *)req_msg.data, &heci_pthi_guid,
- sizeof(struct guid)) == 0) {
- if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) {
- rets = -ENODEV;
- spin_unlock_bh(&dev->device_lock);
- goto end;
- }
- dev->heci_host_clients[file_ext->host_client_id / 8] &=
- ~(1 << (file_ext->host_client_id % 8));
- list_for_each_entry_safe(file_pos,
- file_next, &dev->file_list, link) {
- if (heci_fe_same_id(file_ext, file_pos)) {
- DBG("remove file private data node host"
- " client = %d, ME client = %d.\n",
- file_pos->host_client_id,
- file_pos->me_client_id);
- list_del(&file_pos->link);
- }
-
- }
- DBG("free file private data memory.\n");
- kfree(file_ext);
- file_ext = NULL;
- file->private_data = &dev->iamthif_file_ext;
- client = (struct heci_client *) res_msg.data;
- client->max_msg_length =
- dev->me_clients[i].props.max_msg_length;
- client->protocol_version =
- dev->me_clients[i].props.protocol_version;
- rets = dev->iamthif_file_ext.status;
- spin_unlock_bh(&dev->device_lock);
-
- /* now copy the data to user space */
- if (copy_to_user((void __user *)k_msg.data,
- res_msg.data, res_msg.size)) {
- rets = -EFAULT;
- goto end;
- }
- if (put_user(res_msg.size, &u_msg->size)) {
- rets = -EFAULT;
- goto end;
- }
- goto end;
- }
- spin_unlock_bh(&dev->device_lock);
-
- spin_lock(&file_ext->file_lock);
- spin_lock_bh(&dev->device_lock);
- if (file_ext->state != HECI_FILE_CONNECTING) {
- rets = -ENODEV;
- spin_unlock_bh(&dev->device_lock);
- spin_unlock(&file_ext->file_lock);
- goto end;
- }
- /* prepare the output buffer */
- client = (struct heci_client *) res_msg.data;
- client->max_msg_length = dev->me_clients[i].props.max_msg_length;
- client->protocol_version = dev->me_clients[i].props.protocol_version;
- if (dev->host_buffer_is_empty
- && !other_client_is_connecting(dev, file_ext)) {
- dev->host_buffer_is_empty = 0;
- if (!heci_connect(dev, file_ext)) {
- rets = -ENODEV;
- spin_unlock_bh(&dev->device_lock);
- spin_unlock(&file_ext->file_lock);
- goto end;
- } else {
- file_ext->timer_count = HECI_CONNECT_TIMEOUT;
- priv_cb->file_private = file_ext;
- list_add_tail(&priv_cb->cb_list,
- &dev->ctrl_rd_list.heci_cb.
- cb_list);
- }
-
-
- } else {
- priv_cb->file_private = file_ext;
- DBG("add connect cb to control write list.\n");
- list_add_tail(&priv_cb->cb_list,
- &dev->ctrl_wr_list.heci_cb.cb_list);
- }
- spin_unlock_bh(&dev->device_lock);
- spin_unlock(&file_ext->file_lock);
- err = wait_event_timeout(dev->wait_recvd_msg,
- (HECI_FILE_CONNECTED == file_ext->state
- || HECI_FILE_DISCONNECTED == file_ext->state),
- timeout * HZ);
-
- spin_lock_bh(&dev->device_lock);
- if (HECI_FILE_CONNECTED == file_ext->state) {
- spin_unlock_bh(&dev->device_lock);
- DBG("successfully connected to FW client.\n");
- rets = file_ext->status;
- /* now copy the data to user space */
- if (copy_to_user((void __user *)k_msg.data,
- res_msg.data, res_msg.size)) {
- rets = -EFAULT;
- goto end;
- }
- if (put_user(res_msg.size, &u_msg->size)) {
- rets = -EFAULT;
- goto end;
- }
- goto end;
- } else {
- DBG("failed to connect to FW client.file_ext->state = %d.\n",
- file_ext->state);
- spin_unlock_bh(&dev->device_lock);
- if (!err) {
- DBG("wait_event_interruptible_timeout failed on client"
- " connect message fw response message.\n");
- }
- rets = -EFAULT;
- goto remove_list;
- }
-
-remove_list:
- if (priv_cb) {
- spin_lock_bh(&dev->device_lock);
- heci_flush_list(&dev->ctrl_rd_list, file_ext);
- heci_flush_list(&dev->ctrl_wr_list, file_ext);
- spin_unlock_bh(&dev->device_lock);
- }
-end:
- DBG("free connect cb memory.");
- kfree(req_msg.data);
- kfree(res_msg.data);
- kfree(priv_cb);
- return rets;
-}
-
-/**
- * heci_ioctl_wd - the wd IOCTL function
- *
- * @dev: Device object for our driver
- * @if_num: minor number
- * @k_msg: data in kernel on the stack
- * @file_ext: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int heci_ioctl_wd(struct iamt_heci_device *dev, int if_num,
- struct heci_message_data k_msg,
- struct heci_file_private *file_ext)
-{
- int rets = 0;
- struct heci_message_data req_msg; /*in kernel on the stack */
-
- if (if_num != HECI_MINOR_NUMBER)
- return -ENODEV;
-
- spin_lock(&file_ext->file_lock);
- if (k_msg.size != HECI_WATCHDOG_DATA_SIZE) {
- DBG("user buffer has invalid size.\n");
- spin_unlock(&file_ext->file_lock);
- return -EMSGSIZE;
- }
- spin_unlock(&file_ext->file_lock);
-
- req_msg.data = kmalloc(HECI_WATCHDOG_DATA_SIZE, GFP_KERNEL);
- if (!req_msg.data) {
- DBG("failed allocation request buffer size = %d.\n",
- HECI_WATCHDOG_DATA_SIZE);
- return -ENOMEM;
- }
- req_msg.size = HECI_WATCHDOG_DATA_SIZE;
-
- /* copy the message to kernel space - use a pointer already
- * copied into kernel space
- */
- if (copy_from_user(req_msg.data,
- (void __user *)k_msg.data, req_msg.size)) {
- rets = -EFAULT;
- goto end;
- }
- spin_lock_bh(&dev->device_lock);
- if (dev->heci_state != HECI_ENABLED) {
- rets = -ENODEV;
- spin_unlock_bh(&dev->device_lock);
- goto end;
- }
-
- if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) {
- rets = -ENODEV;
- spin_unlock_bh(&dev->device_lock);
- goto end;
- }
- if (!dev->asf_mode) {
- rets = -EIO;
- spin_unlock_bh(&dev->device_lock);
- goto end;
- }
-
- memcpy(&dev->wd_data[HECI_WD_PARAMS_SIZE], req_msg.data,
- HECI_WATCHDOG_DATA_SIZE);
-
- dev->wd_timeout = (req_msg.data[1] << 8) + req_msg.data[0];
- dev->wd_pending = 0;
- dev->wd_due_counter = 1; /* next timer */
- if (dev->wd_timeout == 0) {
- memcpy(dev->wd_data, heci_stop_wd_params,
- HECI_WD_PARAMS_SIZE);
- } else {
- memcpy(dev->wd_data, heci_start_wd_params,
- HECI_WD_PARAMS_SIZE);
- mod_timer(&dev->wd_timer, jiffies);
- }
- spin_unlock_bh(&dev->device_lock);
-end:
- kfree(req_msg.data);
- return rets;
-}
-
-
-/**
- * heci_ioctl_bypass_wd - the bypass_wd IOCTL function
- *
- * @dev: Device object for our driver
- * @if_num: minor number
- * @k_msg: data in kernel on the stack
- * @file_ext: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num,
- struct heci_message_data k_msg,
- struct heci_file_private *file_ext)
-{
- __u8 flag = 0;
- int rets = 0;
-
- if (if_num != HECI_MINOR_NUMBER)
- return -ENODEV;
-
- spin_lock(&file_ext->file_lock);
- if (k_msg.size < 1) {
- DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE.\n");
- spin_unlock(&file_ext->file_lock);
- return -EMSGSIZE;
- }
- spin_unlock(&file_ext->file_lock);
- if (copy_from_user(&flag, (void __user *)k_msg.data, 1)) {
- rets = -EFAULT;
- goto end;
- }
-
- spin_lock_bh(&dev->device_lock);
- flag = flag ? (1) : (0);
- dev->wd_bypass = flag;
- spin_unlock_bh(&dev->device_lock);
-end:
- return rets;
-}
-
-/**
- * find_pthi_read_list_entry - finds a PTHIlist entry for current file
- *
- * @dev: Device object for our driver
- * @file: pointer to file object
- *
- * returns returned a list entry on success, NULL on failure.
- */
-struct heci_cb_private *find_pthi_read_list_entry(
- struct iamt_heci_device *dev,
- struct file *file)
-{
- struct heci_file_private *file_ext_temp;
- struct heci_cb_private *priv_cb_pos = NULL;
- struct heci_cb_private *priv_cb_next = NULL;
-
- if ((dev->pthi_read_complete_list.status == 0) &&
- !list_empty(&dev->pthi_read_complete_list.heci_cb.cb_list)) {
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &dev->pthi_read_complete_list.heci_cb.cb_list, cb_list) {
- file_ext_temp = (struct heci_file_private *)
- priv_cb_pos->file_private;
- if ((file_ext_temp != NULL) &&
- (file_ext_temp == &dev->iamthif_file_ext) &&
- (priv_cb_pos->file_object == file))
- return priv_cb_pos;
- }
- }
- return NULL;
-}
-
-/**
- * pthi_read - read data from pthi client
- *
- * @dev: Device object for our driver
- * @if_num: minor number
- * @file: pointer to file object
- * @*ubuf: pointer to user data in user space
- * @length: data length to read
- * @offset: data read offset
- *
- * returns
- * returned data length on success,
- * zero if no data to read,
- * negative on failure.
- */
-int pthi_read(struct iamt_heci_device *dev, int if_num, struct file *file,
- char __user *ubuf, size_t length, loff_t *offset)
-{
- int rets = 0;
- struct heci_cb_private *priv_cb = NULL;
- struct heci_file_private *file_ext = file->private_data;
- __u8 i;
- unsigned long currtime = get_seconds();
-
- if ((if_num != HECI_MINOR_NUMBER) || (!dev))
- return -ENODEV;
-
- if ((file_ext == NULL) || (file_ext != &dev->iamthif_file_ext))
- return -ENODEV;
-
- spin_lock_bh(&dev->device_lock);
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (dev->me_clients[i].client_id ==
- dev->iamthif_file_ext.me_client_id)
- break;
- }
- BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id);
- if ((i == dev->num_heci_me_clients)
- || (dev->me_clients[i].client_id !=
- dev->iamthif_file_ext.me_client_id)) {
- DBG("PTHI client not found.\n");
- spin_unlock_bh(&dev->device_lock);
- return -ENODEV;
- }
- priv_cb = find_pthi_read_list_entry(dev, file);
- if (!priv_cb) {
- spin_unlock_bh(&dev->device_lock);
- return 0; /* No more data to read */
- } else {
- if (priv_cb &&
- (currtime - priv_cb->read_time > IAMTHIF_READ_TIMER)) {
- /* 15 sec for the message has expired */
- list_del(&priv_cb->cb_list);
- spin_unlock_bh(&dev->device_lock);
- rets = -ETIMEDOUT;
- goto free;
- }
- /* if the whole message will fit remove it from the list */
- if ((priv_cb->information >= *offset) &&
- (length >= (priv_cb->information - *offset)))
- list_del(&priv_cb->cb_list);
- else if ((priv_cb->information > 0) &&
- (priv_cb->information <= *offset)) {
- /* end of the message has been reached */
- list_del(&priv_cb->cb_list);
- rets = 0;
- spin_unlock_bh(&dev->device_lock);
- goto free;
- }
- /* else means that not full buffer will be read and do not
- * remove message from deletion list
- */
- }
- DBG("pthi priv_cb->response_buffer size - %d\n",
- priv_cb->response_buffer.size);
- DBG("pthi priv_cb->information - %lu\n",
- priv_cb->information);
- spin_unlock_bh(&dev->device_lock);
-
- /* length is being turncated to PAGE_SIZE, however,
- * the information may be longer */
- length = length < (priv_cb->information - *offset) ?
- length : (priv_cb->information - *offset);
-
- if (copy_to_user(ubuf,
- priv_cb->response_buffer.data + *offset,
- length))
- rets = -EFAULT;
- else {
- rets = length;
- if ((*offset + length) < priv_cb->information) {
- *offset += length;
- goto out;
- }
- }
-free:
- DBG("free pthi cb memory.\n");
- *offset = 0;
- heci_free_cb_private(priv_cb);
-out:
- return rets;
-}
-
-/**
- * heci_start_read - the start read client message function.
- *
- * @dev: Device object for our driver
- * @if_num: minor number
- * @file_ext: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int heci_start_read(struct iamt_heci_device *dev, int if_num,
- struct heci_file_private *file_ext)
-{
- int rets = 0;
- __u8 i;
- struct heci_cb_private *priv_cb = NULL;
-
- if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) {
- DBG("received wrong function input param.\n");
- return -ENODEV;
- }
-
- spin_lock_bh(&dev->device_lock);
- if (file_ext->state != HECI_FILE_CONNECTED) {
- spin_unlock_bh(&dev->device_lock);
- return -ENODEV;
- }
-
- if (dev->heci_state != HECI_ENABLED) {
- spin_unlock_bh(&dev->device_lock);
- return -ENODEV;
- }
- spin_unlock_bh(&dev->device_lock);
- DBG("check if read is pending.\n");
- spin_lock_bh(&file_ext->read_io_lock);
- if ((file_ext->read_pending) || (file_ext->read_cb != NULL)) {
- DBG("read is pending.\n");
- spin_unlock_bh(&file_ext->read_io_lock);
- return -EBUSY;
- }
- spin_unlock_bh(&file_ext->read_io_lock);
-
- priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
- if (!priv_cb)
- return -ENOMEM;
-
- spin_lock_bh(&file_ext->read_io_lock);
- DBG("allocation call back success\n"
- "host client = %d, ME client = %d\n",
- file_ext->host_client_id, file_ext->me_client_id);
- spin_unlock_bh(&file_ext->read_io_lock);
-
- spin_lock_bh(&dev->device_lock);
- spin_lock_bh(&file_ext->read_io_lock);
- for (i = 0; i < dev->num_heci_me_clients; i++) {
- if (dev->me_clients[i].client_id == file_ext->me_client_id)
- break;
-
- }
-
- BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id);
- spin_unlock_bh(&file_ext->read_io_lock);
- if (i == dev->num_heci_me_clients) {
- rets = -ENODEV;
- goto unlock;
- }
-
- priv_cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
- spin_unlock_bh(&dev->device_lock);
- priv_cb->response_buffer.data =
- kmalloc(priv_cb->response_buffer.size, GFP_KERNEL);
- if (!priv_cb->response_buffer.data) {
- rets = -ENOMEM;
- goto fail;
- }
- DBG("allocation call back data success.\n");
- priv_cb->major_file_operations = HECI_READ;
- /* make sure information is zero before we start */
- priv_cb->information = 0;
- priv_cb->file_private = (void *) file_ext;
- spin_lock_bh(&dev->device_lock);
- spin_lock_bh(&file_ext->read_io_lock);
- file_ext->read_cb = priv_cb;
- if (dev->host_buffer_is_empty) {
- dev->host_buffer_is_empty = 0;
- if (!heci_send_flow_control(dev, file_ext)) {
- rets = -ENODEV;
- spin_unlock_bh(&file_ext->read_io_lock);
- goto unlock;
- } else {
- list_add_tail(&priv_cb->cb_list,
- &dev->read_list.heci_cb.cb_list);
- }
- } else {
- list_add_tail(&priv_cb->cb_list,
- &dev->ctrl_wr_list.heci_cb.cb_list);
- }
- spin_unlock_bh(&file_ext->read_io_lock);
- spin_unlock_bh(&dev->device_lock);
- return rets;
-unlock:
- spin_unlock_bh(&dev->device_lock);
-fail:
- heci_free_cb_private(priv_cb);
- return rets;
-}
-
-/**
- * pthi_write - write iamthif data to pthi client
- *
- * @dev: Device object for our driver
- * @priv_cb: heci call back struct
- *
- * returns 0 on success, <0 on failure.
- */
-int pthi_write(struct iamt_heci_device *dev,
- struct heci_cb_private *priv_cb)
-{
- int rets = 0;
- struct heci_msg_hdr heci_hdr;
-
- if ((!dev) || (!priv_cb))
- return -ENODEV;
-
- DBG("write data to pthi client.\n");
-
- dev->iamthif_state = HECI_IAMTHIF_WRITING;
- dev->iamthif_current_cb = priv_cb;
- dev->iamthif_file_object = priv_cb->file_object;
- dev->iamthif_canceled = 0;
- dev->iamthif_ioctl = 1;
- dev->iamthif_msg_buf_size = priv_cb->request_buffer.size;
- memcpy(dev->iamthif_msg_buf, priv_cb->request_buffer.data,
- priv_cb->request_buffer.size);
-
- if (flow_ctrl_creds(dev, &dev->iamthif_file_ext) &&
- dev->host_buffer_is_empty) {
- dev->host_buffer_is_empty = 0;
- if (priv_cb->request_buffer.size >
- (((dev->host_hw_state & H_CBD) >> 24) *
- sizeof(__u32)) - sizeof(struct heci_msg_hdr)) {
- heci_hdr.length =
- (((dev->host_hw_state & H_CBD) >> 24) *
- sizeof(__u32)) - sizeof(struct heci_msg_hdr);
- heci_hdr.msg_complete = 0;
- } else {
- heci_hdr.length = priv_cb->request_buffer.size;
- heci_hdr.msg_complete = 1;
- }
-
- heci_hdr.host_addr = dev->iamthif_file_ext.host_client_id;
- heci_hdr.me_addr = dev->iamthif_file_ext.me_client_id;
- heci_hdr.reserved = 0;
- dev->iamthif_msg_buf_index += heci_hdr.length;
- if (!heci_write_message(dev, &heci_hdr,
- (unsigned char *)(dev->iamthif_msg_buf),
- heci_hdr.length))
- return -ENODEV;
-
- if (heci_hdr.msg_complete) {
- flow_ctrl_reduce(dev, &dev->iamthif_file_ext);
- dev->iamthif_flow_control_pending = 1;
- dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL;
- DBG("add pthi cb to write waiting list\n");
- dev->iamthif_current_cb = priv_cb;
- dev->iamthif_file_object = priv_cb->file_object;
- list_add_tail(&priv_cb->cb_list,
- &dev->write_waiting_list.heci_cb.cb_list);
- } else {
- DBG("message does not complete, "
- "so add pthi cb to write list.\n");
- list_add_tail(&priv_cb->cb_list,
- &dev->write_list.heci_cb.cb_list);
- }
- } else {
- if (!(dev->host_buffer_is_empty))
- DBG("host buffer is not empty");
-
- DBG("No flow control credentials, "
- "so add iamthif cb to write list.\n");
- list_add_tail(&priv_cb->cb_list,
- &dev->write_list.heci_cb.cb_list);
- }
- return rets;
-}
-
-/**
- * iamthif_ioctl_send_msg - send cmd data to pthi client
- *
- * @dev: Device object for our driver
- *
- * returns 0 on success, <0 on failure.
- */
-void run_next_iamthif_cmd(struct iamt_heci_device *dev)
-{
- struct heci_file_private *file_ext_tmp;
- struct heci_cb_private *priv_cb_pos = NULL;
- struct heci_cb_private *priv_cb_next = NULL;
- int status = 0;
-
- if (!dev)
- return;
-
- dev->iamthif_msg_buf_size = 0;
- dev->iamthif_msg_buf_index = 0;
- dev->iamthif_canceled = 0;
- dev->iamthif_ioctl = 1;
- dev->iamthif_state = HECI_IAMTHIF_IDLE;
- dev->iamthif_timer = 0;
- dev->iamthif_file_object = NULL;
-
- if (dev->pthi_cmd_list.status == 0 &&
- !list_empty(&dev->pthi_cmd_list.heci_cb.cb_list)) {
- DBG("complete pthi cmd_list cb.\n");
-
- list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
- &dev->pthi_cmd_list.heci_cb.cb_list, cb_list) {
- list_del(&priv_cb_pos->cb_list);
- file_ext_tmp = (struct heci_file_private *)
- priv_cb_pos->file_private;
-
- if ((file_ext_tmp != NULL) &&
- (file_ext_tmp == &dev->iamthif_file_ext)) {
- status = pthi_write(dev, priv_cb_pos);
- if (status != 0) {
- DBG("pthi write failed status = %d\n",
- status);
- return;
- }
- break;
- }
- }
- }
-}
-
-/**
- * heci_free_cb_private - free heci_cb_private related memory
- *
- * @priv_cb: heci callback struct
- */
-void heci_free_cb_private(struct heci_cb_private *priv_cb)
-{
- if (priv_cb == NULL)
- return;
-
- kfree(priv_cb->request_buffer.data);
- kfree(priv_cb->response_buffer.data);
- kfree(priv_cb);
-}
-