]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
Staging: mei: move the mei code out of staging
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 May 2012 22:23:38 +0000 (18:23 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 May 2012 22:23:38 +0000 (18:23 -0400)
It's been cleaned up, and there's nothing else left to do, so move it
out of staging into drivers/misc/ where all can use it now.

Cc: Tomas Winkler <tomas.winkler@intel.com>
Cc: Oren Weil <oren.jer.weil@intel.com>
Cc: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
34 files changed:
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/mei/Kconfig [new file with mode: 0644]
drivers/misc/mei/Makefile [new file with mode: 0644]
drivers/misc/mei/TODO [new file with mode: 0644]
drivers/misc/mei/hw.h [new file with mode: 0644]
drivers/misc/mei/init.c [new file with mode: 0644]
drivers/misc/mei/interface.c [new file with mode: 0644]
drivers/misc/mei/interface.h [new file with mode: 0644]
drivers/misc/mei/interrupt.c [new file with mode: 0644]
drivers/misc/mei/iorw.c [new file with mode: 0644]
drivers/misc/mei/main.c [new file with mode: 0644]
drivers/misc/mei/mei-amt-version.c [new file with mode: 0644]
drivers/misc/mei/mei.h [new file with mode: 0644]
drivers/misc/mei/mei.txt [new file with mode: 0644]
drivers/misc/mei/mei_dev.h [new file with mode: 0644]
drivers/misc/mei/wd.c [new file with mode: 0644]
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/mei/Kconfig [deleted file]
drivers/staging/mei/Makefile [deleted file]
drivers/staging/mei/TODO [deleted file]
drivers/staging/mei/hw.h [deleted file]
drivers/staging/mei/init.c [deleted file]
drivers/staging/mei/interface.c [deleted file]
drivers/staging/mei/interface.h [deleted file]
drivers/staging/mei/interrupt.c [deleted file]
drivers/staging/mei/iorw.c [deleted file]
drivers/staging/mei/main.c [deleted file]
drivers/staging/mei/mei-amt-version.c [deleted file]
drivers/staging/mei/mei.h [deleted file]
drivers/staging/mei/mei.txt [deleted file]
drivers/staging/mei/mei_dev.h [deleted file]
drivers/staging/mei/wd.c [deleted file]

index c7795096d43bc22c4450ba8b6c88a88a9be1c19e..c9104282ec956159eef34cb616204633cf97aaa5 100644 (file)
@@ -506,4 +506,5 @@ source "drivers/misc/ti-st/Kconfig"
 source "drivers/misc/lis3lv02d/Kconfig"
 source "drivers/misc/carma/Kconfig"
 source "drivers/misc/altera-stapl/Kconfig"
+source "drivers/misc/mei/Kconfig"
 endmenu
index 3e1d80106f04e36fad4b82806b8939afcfae50cc..0f6af6a13345e0f2ce4c43791e9a26b2574a8cab 100644 (file)
@@ -49,3 +49,4 @@ obj-y                         += carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
 obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
 obj-$(CONFIG_MAX8997_MUIC)     += max8997-muic.o
+obj-$(CONFIG_INTEL_MEI)                += mei/
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
new file mode 100644 (file)
index 0000000..47d78a7
--- /dev/null
@@ -0,0 +1,28 @@
+config INTEL_MEI
+       tristate "Intel Management Engine Interface (Intel MEI)"
+       depends on X86 && PCI && EXPERIMENTAL && WATCHDOG_CORE
+       help
+         The Intel Management Engine (Intel ME) provides Manageability,
+         Security and Media services for system containing Intel chipsets.
+         if selected /dev/mei misc device will be created.
+
+         Supported Chipsets are:
+         7 Series Chipset Family
+         6 Series Chipset Family
+         5 Series Chipset Family
+         4 Series Chipset Family
+         Mobile 4 Series Chipset Family
+         ICH9
+         82946GZ/GL
+         82G35 Express
+         82Q963/Q965
+         82P965/G965
+         Mobile PM965/GM965
+         Mobile GME965/GLE960
+         82Q35 Express
+         82G33/G31/P35/P31 Express
+         82Q33 Express
+         82X38/X48 Express
+
+         For more information see
+         <http://software.intel.com/en-us/manageability/>
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
new file mode 100644 (file)
index 0000000..57168db
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile - Intel Management Engine Interface (Intel MEI) Linux driver
+# Copyright (c) 2010-2011, Intel Corporation.
+#
+obj-$(CONFIG_INTEL_MEI) += mei.o
+mei-objs := init.o
+mei-objs += interrupt.o
+mei-objs += interface.o
+mei-objs += iorw.o
+mei-objs += main.o
+mei-objs += wd.o
diff --git a/drivers/misc/mei/TODO b/drivers/misc/mei/TODO
new file mode 100644 (file)
index 0000000..fc26601
--- /dev/null
@@ -0,0 +1,10 @@
+TODO:
+       - Cleanup and split the timer function
+Upon Unstaging:
+       - move mei.h to include/linux/mei.h
+       - Documentation/ioctl/ioctl-number.txt
+       - move mei.txt under Documentation/mei/
+       - move mei-amt-version.c under Documentation/mei
+       - add hostprogs-y for mei-amt-version.c
+       - drop mei_version.h
+       - Updated MAINTAINERS
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
new file mode 100644 (file)
index 0000000..24c4c96
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _MEI_HW_TYPES_H_
+#define _MEI_HW_TYPES_H_
+
+#include <linux/uuid.h>
+
+/*
+ * Timeouts
+ */
+#define MEI_INTEROP_TIMEOUT    (HZ * 7)
+#define MEI_CONNECT_TIMEOUT            3       /* at least 2 seconds */
+
+#define CONNECT_TIMEOUT        15      /* HPS definition */
+#define INIT_CLIENTS_TIMEOUT   15      /* HPS definition */
+
+#define IAMTHIF_STALL_TIMER            12      /* seconds */
+#define IAMTHIF_READ_TIMER             10000   /* ms */
+
+/*
+ * Internal Clients Number
+ */
+#define MEI_WD_HOST_CLIENT_ID          1
+#define MEI_IAMTHIF_HOST_CLIENT_ID     2
+
+/*
+ * MEI device IDs
+ */
+#define    MEI_DEV_ID_82946GZ  0x2974  /* 82946GZ/GL */
+#define    MEI_DEV_ID_82G35    0x2984  /* 82G35 Express */
+#define    MEI_DEV_ID_82Q965   0x2994  /* 82Q963/Q965 */
+#define    MEI_DEV_ID_82G965   0x29A4  /* 82P965/G965 */
+
+#define    MEI_DEV_ID_82GM965  0x2A04  /* Mobile PM965/GM965 */
+#define    MEI_DEV_ID_82GME965 0x2A14  /* Mobile GME965/GLE960 */
+
+#define    MEI_DEV_ID_ICH9_82Q35 0x29B4  /* 82Q35 Express */
+#define    MEI_DEV_ID_ICH9_82G33 0x29C4  /* 82G33/G31/P35/P31 Express */
+#define    MEI_DEV_ID_ICH9_82Q33 0x29D4  /* 82Q33 Express */
+#define    MEI_DEV_ID_ICH9_82X38 0x29E4  /* 82X38/X48 Express */
+#define    MEI_DEV_ID_ICH9_3200  0x29F4  /* 3200/3210 Server */
+
+#define    MEI_DEV_ID_ICH9_6   0x28B4  /* Bearlake */
+#define    MEI_DEV_ID_ICH9_7   0x28C4  /* Bearlake */
+#define    MEI_DEV_ID_ICH9_8   0x28D4  /* Bearlake */
+#define    MEI_DEV_ID_ICH9_9    0x28E4  /* Bearlake */
+#define    MEI_DEV_ID_ICH9_10  0x28F4  /* Bearlake */
+
+#define    MEI_DEV_ID_ICH9M_1  0x2A44  /* Cantiga */
+#define    MEI_DEV_ID_ICH9M_2  0x2A54  /* Cantiga */
+#define    MEI_DEV_ID_ICH9M_3  0x2A64  /* Cantiga */
+#define    MEI_DEV_ID_ICH9M_4  0x2A74  /* Cantiga */
+
+#define    MEI_DEV_ID_ICH10_1  0x2E04  /* Eaglelake */
+#define    MEI_DEV_ID_ICH10_2  0x2E14  /* Eaglelake */
+#define    MEI_DEV_ID_ICH10_3  0x2E24  /* Eaglelake */
+#define    MEI_DEV_ID_ICH10_4  0x2E34  /* Eaglelake */
+
+#define    MEI_DEV_ID_IBXPK_1  0x3B64  /* Calpella */
+#define    MEI_DEV_ID_IBXPK_2  0x3B65  /* Calpella */
+
+#define    MEI_DEV_ID_CPT_1    0x1C3A    /* Cougerpoint */
+#define    MEI_DEV_ID_PBG_1    0x1D3A    /* PBG */
+
+#define    MEI_DEV_ID_PPT_1    0x1E3A    /* Pantherpoint PPT */
+#define    MEI_DEV_ID_PPT_2    0x1CBA    /* Pantherpoint PPT */
+#define    MEI_DEV_ID_PPT_3    0x1DBA    /* Pantherpoint PPT */
+
+
+/*
+ * MEI HW Section
+ */
+
+/* MEI 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
+
+/*
+ * MEI Version
+ */
+#define HBM_MINOR_VERSION                   0
+#define HBM_MAJOR_VERSION                   1
+#define HBM_TIMEOUT                         1  /* 1 second */
+
+/* Host bus message command opcode */
+#define MEI_HBM_CMD_OP_MSK                  0x7f
+/* Host bus message command RESPONSE */
+#define MEI_HBM_CMD_RES_MSK                 0x80
+
+/*
+ * MEI Bus Message Command IDs
+ */
+#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_PROPERTIES_REQ_CMD      0x05
+#define HOST_CLIENT_PROPERTIES_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 MEI_FLOW_CONTROL_CMD                0x08
+
+/*
+ * MEI Stop Reason
+ * used by hbm_host_stop_request.reason
+ */
+enum mei_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
+};
+
+/*
+ * Client Connect Status
+ * used by hbm_client_connect_response.status
+ */
+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
+};
+
+/*
+ * Client Disconnect Status
+ */
+enum client_disconnect_status_types {
+       CDS_SUCCESS = 0x00
+};
+
+/*
+ *  MEI BUS Interface Section
+ */
+struct mei_msg_hdr {
+       u32 me_addr:8;
+       u32 host_addr:8;
+       u32 length:9;
+       u32 reserved:6;
+       u32 msg_complete:1;
+} __packed;
+
+
+struct mei_bus_message {
+       u8 hbm_cmd;
+       u8 data[0];
+} __packed;
+
+struct hbm_version {
+       u8 minor_version;
+       u8 major_version;
+} __packed;
+
+struct hbm_host_version_request {
+       u8 hbm_cmd;
+       u8 reserved;
+       struct hbm_version host_version;
+} __packed;
+
+struct hbm_host_version_response {
+       u8 hbm_cmd;
+       u8 host_version_supported;
+       struct hbm_version me_max_version;
+} __packed;
+
+struct hbm_host_stop_request {
+       u8 hbm_cmd;
+       u8 reason;
+       u8 reserved[2];
+} __packed;
+
+struct hbm_host_stop_response {
+       u8 hbm_cmd;
+       u8 reserved[3];
+} __packed;
+
+struct hbm_me_stop_request {
+       u8 hbm_cmd;
+       u8 reason;
+       u8 reserved[2];
+} __packed;
+
+struct hbm_host_enum_request {
+       u8 hbm_cmd;
+       u8 reserved[3];
+} __packed;
+
+struct hbm_host_enum_response {
+       u8 hbm_cmd;
+       u8 reserved[3];
+       u8 valid_addresses[32];
+} __packed;
+
+struct mei_client_properties {
+       uuid_le protocol_name;
+       u8 protocol_version;
+       u8 max_number_of_connections;
+       u8 fixed_address;
+       u8 single_recv_buf;
+       u32 max_msg_length;
+} __packed;
+
+struct hbm_props_request {
+       u8 hbm_cmd;
+       u8 address;
+       u8 reserved[2];
+} __packed;
+
+
+struct hbm_props_response {
+       u8 hbm_cmd;
+       u8 address;
+       u8 status;
+       u8 reserved[1];
+       struct mei_client_properties client_properties;
+} __packed;
+
+struct hbm_client_connect_request {
+       u8 hbm_cmd;
+       u8 me_addr;
+       u8 host_addr;
+       u8 reserved;
+} __packed;
+
+struct hbm_client_connect_response {
+       u8 hbm_cmd;
+       u8 me_addr;
+       u8 host_addr;
+       u8 status;
+} __packed;
+
+struct hbm_client_disconnect_request {
+       u8 hbm_cmd;
+       u8 me_addr;
+       u8 host_addr;
+       u8 reserved[1];
+} __packed;
+
+#define MEI_FC_MESSAGE_RESERVED_LENGTH           5
+
+struct hbm_flow_control {
+       u8 hbm_cmd;
+       u8 me_addr;
+       u8 host_addr;
+       u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH];
+} __packed;
+
+struct mei_me_client {
+       struct mei_client_properties props;
+       u8 client_id;
+       u8 mei_flow_ctrl_creds;
+} __packed;
+
+
+#endif
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
new file mode 100644 (file)
index 0000000..afb0a58
--- /dev/null
@@ -0,0 +1,735 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include "mei_dev.h"
+#include "hw.h"
+#include "interface.h"
+#include "mei.h"
+
+const uuid_le mei_amthi_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
+                                               0xa8, 0x46, 0xe0, 0xff, 0x65,
+                                               0x81, 0x4c);
+
+/**
+ * mei_io_list_init - Sets up a queue list.
+ *
+ * @list: An instance io list structure
+ * @dev: the device structure
+ */
+void mei_io_list_init(struct mei_io_list *list)
+{
+       /* initialize our queue list */
+       INIT_LIST_HEAD(&list->mei_cb.cb_list);
+}
+
+/**
+ * mei_io_list_flush - removes list entry belonging to cl.
+ *
+ * @list:  An instance of our list structure
+ * @cl: private data of the file object
+ */
+void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl)
+{
+       struct mei_cl_cb *pos;
+       struct mei_cl_cb *next;
+
+       list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) {
+               if (pos->file_private) {
+                       struct mei_cl *cl_tmp;
+                       cl_tmp = (struct mei_cl *)pos->file_private;
+                       if (mei_cl_cmp_id(cl, cl_tmp))
+                               list_del(&pos->cb_list);
+               }
+       }
+}
+/**
+ * mei_cl_flush_queues - flushes queue lists belonging to cl.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ */
+int mei_cl_flush_queues(struct mei_cl *cl)
+{
+       if (!cl || !cl->dev)
+               return -EINVAL;
+
+       dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
+       mei_io_list_flush(&cl->dev->read_list, cl);
+       mei_io_list_flush(&cl->dev->write_list, cl);
+       mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+       mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
+       mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
+       mei_io_list_flush(&cl->dev->amthi_cmd_list, cl);
+       mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl);
+       return 0;
+}
+
+
+
+/**
+ * mei_reset_iamthif_params - initializes mei device iamthif
+ *
+ * @dev: the device structure
+ */
+static void mei_reset_iamthif_params(struct mei_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 = false;
+       dev->iamthif_ioctl = false;
+       dev->iamthif_state = MEI_IAMTHIF_IDLE;
+       dev->iamthif_timer = 0;
+}
+
+/**
+ * init_mei_device - allocates and initializes the mei device structure
+ *
+ * @pdev: The pci device structure
+ *
+ * returns The mei_device_device pointer on success, NULL on failure.
+ */
+struct mei_device *mei_device_init(struct pci_dev *pdev)
+{
+       struct mei_device *dev;
+
+       dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       /* setup our list array */
+       INIT_LIST_HEAD(&dev->file_list);
+       INIT_LIST_HEAD(&dev->wd_cl.link);
+       INIT_LIST_HEAD(&dev->iamthif_cl.link);
+       mutex_init(&dev->device_lock);
+       init_waitqueue_head(&dev->wait_recvd_msg);
+       init_waitqueue_head(&dev->wait_stop_wd);
+       dev->mei_state = MEI_INITIALIZING;
+       dev->iamthif_state = MEI_IAMTHIF_IDLE;
+       dev->wd_interface_reg = false;
+
+
+       mei_io_list_init(&dev->read_list);
+       mei_io_list_init(&dev->write_list);
+       mei_io_list_init(&dev->write_waiting_list);
+       mei_io_list_init(&dev->ctrl_wr_list);
+       mei_io_list_init(&dev->ctrl_rd_list);
+       mei_io_list_init(&dev->amthi_cmd_list);
+       mei_io_list_init(&dev->amthi_read_complete_list);
+       dev->pdev = pdev;
+       return dev;
+}
+
+/**
+ * mei_hw_init - initializes host and fw to start work.
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_hw_init(struct mei_device *dev)
+{
+       int err = 0;
+       int ret;
+
+       mutex_lock(&dev->device_lock);
+
+       dev->host_hw_state = mei_hcsr_read(dev);
+       dev->me_hw_state = mei_mecsr_read(dev);
+       dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n",
+           dev->host_hw_state, dev->me_hw_state);
+
+       /* acknowledge interrupt and stop interupts */
+       if ((dev->host_hw_state & H_IS) == H_IS)
+               mei_reg_write(dev, H_CSR, dev->host_hw_state);
+
+       dev->recvd_msg = false;
+       dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
+
+       mei_reset(dev, 1);
+
+       dev_dbg(&dev->pdev->dev, "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) {
+               mutex_unlock(&dev->device_lock);
+               err = wait_event_interruptible_timeout(dev->wait_recvd_msg,
+                       dev->recvd_msg, MEI_INTEROP_TIMEOUT);
+               mutex_lock(&dev->device_lock);
+       }
+
+       if (err <= 0 && !dev->recvd_msg) {
+               dev->mei_state = MEI_DISABLED;
+               dev_dbg(&dev->pdev->dev,
+                       "wait_event_interruptible_timeout failed"
+                       "on wait for ME to turn on ME_RDY.\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
+             ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
+               dev->mei_state = MEI_DISABLED;
+               dev_dbg(&dev->pdev->dev,
+                       "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))
+                       dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n");
+
+               if (!(dev->me_hw_state & ME_RDY_HRA))
+                       dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
+
+               dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (dev->version.major_version != HBM_MAJOR_VERSION ||
+           dev->version.minor_version != HBM_MINOR_VERSION) {
+               dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       dev->recvd_msg = false;
+       dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
+           dev->host_hw_state, dev->me_hw_state);
+       dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n");
+       dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
+       dev_dbg(&dev->pdev->dev, "MEI  start success.\n");
+       ret = 0;
+
+out:
+       mutex_unlock(&dev->device_lock);
+       return ret;
+}
+
+/**
+ * mei_hw_reset - resets fw via mei csr register.
+ *
+ * @dev: the device structure
+ * @interrupts_enabled: if interrupt should be enabled after reset.
+ */
+static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled)
+{
+       dev->host_hw_state |= (H_RST | H_IG);
+
+       if (interrupts_enabled)
+               mei_enable_interrupts(dev);
+       else
+               mei_disable_interrupts(dev);
+}
+
+/**
+ * mei_reset - resets host and fw.
+ *
+ * @dev: the device structure
+ * @interrupts_enabled: if interrupt should be enabled after reset.
+ */
+void mei_reset(struct mei_device *dev, int interrupts_enabled)
+{
+       struct mei_cl *cl_pos = NULL;
+       struct mei_cl *cl_next = NULL;
+       struct mei_cl_cb *cb_pos = NULL;
+       struct mei_cl_cb *cb_next = NULL;
+       bool unexpected;
+
+       if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
+               dev->need_reset = true;
+               return;
+       }
+
+       unexpected = (dev->mei_state != MEI_INITIALIZING &&
+                       dev->mei_state != MEI_DISABLED &&
+                       dev->mei_state != MEI_POWER_DOWN &&
+                       dev->mei_state != MEI_POWER_UP);
+
+       dev->host_hw_state = mei_hcsr_read(dev);
+
+       dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n",
+           dev->host_hw_state);
+
+       mei_hw_reset(dev, interrupts_enabled);
+
+       dev->host_hw_state &= ~H_RST;
+       dev->host_hw_state |= H_IG;
+
+       mei_hcsr_set(dev);
+
+       dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n",
+           dev->host_hw_state);
+
+       dev->need_reset = false;
+
+       if (dev->mei_state != MEI_INITIALIZING) {
+               if (dev->mei_state != MEI_DISABLED &&
+                   dev->mei_state != MEI_POWER_DOWN)
+                       dev->mei_state = MEI_RESETING;
+
+               list_for_each_entry_safe(cl_pos,
+                               cl_next, &dev->file_list, link) {
+                       cl_pos->state = MEI_FILE_DISCONNECTED;
+                       cl_pos->mei_flow_ctrl_creds = 0;
+                       cl_pos->read_cb = NULL;
+                       cl_pos->timer_count = 0;
+               }
+               /* remove entry if already in list */
+               dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n");
+               mei_remove_client_from_file_list(dev,
+                               dev->wd_cl.host_client_id);
+
+               mei_remove_client_from_file_list(dev,
+                               dev->iamthif_cl.host_client_id);
+
+               mei_reset_iamthif_params(dev);
+               dev->wd_due_counter = 0;
+               dev->extra_write_index = 0;
+       }
+
+       dev->me_clients_num = 0;
+       dev->rd_msg_hdr = 0;
+       dev->stop = false;
+       dev->wd_pending = false;
+
+       /* update the state of the registers after reset */
+       dev->host_hw_state = mei_hcsr_read(dev);
+       dev->me_hw_state = mei_mecsr_read(dev);
+
+       dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
+           dev->host_hw_state, dev->me_hw_state);
+
+       if (unexpected)
+               dev_warn(&dev->pdev->dev, "unexpected reset.\n");
+
+       /* Wake up all readings so they can be interrupted */
+       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+               if (waitqueue_active(&cl_pos->rx_wait)) {
+                       dev_dbg(&dev->pdev->dev, "Waking up client!\n");
+                       wake_up_interruptible(&cl_pos->rx_wait);
+               }
+       }
+       /* remove all waiting requests */
+       list_for_each_entry_safe(cb_pos, cb_next,
+                       &dev->write_list.mei_cb.cb_list, cb_list) {
+               list_del(&cb_pos->cb_list);
+               mei_free_cb_private(cb_pos);
+       }
+}
+
+
+
+/**
+ * host_start_message - mei host sends start message.
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+void mei_host_start_message(struct mei_device *dev)
+{
+       struct mei_msg_hdr *mei_hdr;
+       struct hbm_host_version_request *host_start_req;
+
+       /* host start message */
+       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+       mei_hdr->host_addr = 0;
+       mei_hdr->me_addr = 0;
+       mei_hdr->length = sizeof(struct hbm_host_version_request);
+       mei_hdr->msg_complete = 1;
+       mei_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->hbm_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 = false;
+       if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
+                                      mei_hdr->length)) {
+               dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
+               dev->mei_state = MEI_RESETING;
+               mei_reset(dev, 1);
+       }
+       dev->init_clients_state = MEI_START_MESSAGE;
+       dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
+       return ;
+}
+
+/**
+ * host_enum_clients_message - host sends enumeration client request message.
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+void mei_host_enum_clients_message(struct mei_device *dev)
+{
+       struct mei_msg_hdr *mei_hdr;
+       struct hbm_host_enum_request *host_enum_req;
+       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+       /* enumerate clients */
+       mei_hdr->host_addr = 0;
+       mei_hdr->me_addr = 0;
+       mei_hdr->length = sizeof(struct hbm_host_enum_request);
+       mei_hdr->msg_complete = 1;
+       mei_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->hbm_cmd = HOST_ENUM_REQ_CMD;
+       if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
+                               mei_hdr->length)) {
+               dev->mei_state = MEI_RESETING;
+               dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
+               mei_reset(dev, 1);
+       }
+       dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
+       dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
+       return;
+}
+
+
+/**
+ * allocate_me_clients_storage - allocates storage for me clients
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+void mei_allocate_me_clients_storage(struct mei_device *dev)
+{
+       struct mei_me_client *clients;
+       int b;
+
+       /* count how many ME clients we have */
+       for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
+               dev->me_clients_num++;
+
+       if (dev->me_clients_num <= 0)
+               return ;
+
+
+       if (dev->me_clients != NULL) {
+               kfree(dev->me_clients);
+               dev->me_clients = NULL;
+       }
+       dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
+               dev->me_clients_num * sizeof(struct mei_me_client));
+       /* allocate storage for ME clients representation */
+       clients = kcalloc(dev->me_clients_num,
+                       sizeof(struct mei_me_client), GFP_KERNEL);
+       if (!clients) {
+               dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
+               dev->mei_state = MEI_RESETING;
+               mei_reset(dev, 1);
+               return ;
+       }
+       dev->me_clients = clients;
+       return ;
+}
+/**
+ * host_client_properties - reads properties for client
+ *
+ * @dev: the device structure
+ *
+ * returns:
+ *     < 0 - Error.
+ *  = 0 - no more clients.
+ *  = 1 - still have clients to send properties request.
+ */
+int mei_host_client_properties(struct mei_device *dev)
+{
+       struct mei_msg_hdr *mei_header;
+       struct hbm_props_request *host_cli_req;
+       int b;
+       u8 client_num = dev->me_client_presentation_num;
+
+       b = dev->me_client_index;
+       b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b);
+       if (b < MEI_CLIENTS_MAX) {
+               dev->me_clients[client_num].client_id = b;
+               dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
+               mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
+               mei_header->host_addr = 0;
+               mei_header->me_addr = 0;
+               mei_header->length = sizeof(struct hbm_props_request);
+               mei_header->msg_complete = 1;
+               mei_header->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->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
+               host_cli_req->address = b;
+
+               if (mei_write_message(dev, mei_header,
+                               (unsigned char *)host_cli_req,
+                               mei_header->length)) {
+                       dev->mei_state = MEI_RESETING;
+                       dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
+                       mei_reset(dev, 1);
+                       return -EIO;
+               }
+
+               dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
+               dev->me_client_index = b;
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * mei_init_file_private - initializes private file structure.
+ *
+ * @priv: private file structure to be initialized
+ * @file: the file structure
+ */
+void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
+{
+       memset(priv, 0, sizeof(struct mei_cl));
+       init_waitqueue_head(&priv->wait);
+       init_waitqueue_head(&priv->rx_wait);
+       init_waitqueue_head(&priv->tx_wait);
+       INIT_LIST_HEAD(&priv->link);
+       priv->reading_state = MEI_IDLE;
+       priv->writing_state = MEI_IDLE;
+       priv->dev = dev;
+}
+
+int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
+{
+       int i, res = -1;
+
+       for (i = 0; i < dev->me_clients_num; ++i)
+               if (uuid_le_cmp(cuuid,
+                               dev->me_clients[i].props.protocol_name) == 0) {
+                       res = i;
+                       break;
+               }
+
+       return res;
+}
+
+
+/**
+ * mei_find_me_client_update_filext - searches for ME client guid
+ *                       sets client_id in mei_file_private if found
+ * @dev: the device structure
+ * @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
+ */
+u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
+                               const uuid_le *cguid, u8 client_id)
+{
+       int i;
+
+       if (!dev || !priv || !cguid)
+               return 0;
+
+       /* check for valid client id */
+       i = mei_find_me_client_index(dev, *cguid);
+       if (i >= 0) {
+               priv->me_client_id = dev->me_clients[i].client_id;
+               priv->state = MEI_FILE_CONNECTING;
+               priv->host_client_id = client_id;
+
+               list_add_tail(&priv->link, &dev->file_list);
+               return (u8)i;
+       }
+
+       return 0;
+}
+
+/**
+ * host_init_iamthif - mei initialization iamthif client.
+ *
+ * @dev: the device structure
+ *
+ */
+void mei_host_init_iamthif(struct mei_device *dev)
+{
+       u8 i;
+       unsigned char *msg_buf;
+
+       mei_cl_init(&dev->iamthif_cl, dev);
+       dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
+
+       /* find ME amthi client */
+       i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
+                           &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
+       if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
+               dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
+               return;
+       }
+
+       /* Assign iamthif_mtu to the value received from ME  */
+
+       dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
+       dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
+                       dev->me_clients[i].props.max_msg_length);
+
+       kfree(dev->iamthif_msg_buf);
+       dev->iamthif_msg_buf = NULL;
+
+       /* allocate storage for ME message buffer */
+       msg_buf = kcalloc(dev->iamthif_mtu,
+                       sizeof(unsigned char), GFP_KERNEL);
+       if (!msg_buf) {
+               dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n");
+               return;
+       }
+
+       dev->iamthif_msg_buf = msg_buf;
+
+       if (mei_connect(dev, &dev->iamthif_cl)) {
+               dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
+               dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
+               dev->iamthif_cl.host_client_id = 0;
+       } else {
+               dev->iamthif_cl.timer_count = CONNECT_TIMEOUT;
+       }
+}
+
+/**
+ * mei_alloc_file_private - allocates a private file structure and sets it up.
+ * @file: the file structure
+ *
+ * returns  The allocated file or NULL on failure
+ */
+struct mei_cl *mei_cl_allocate(struct mei_device *dev)
+{
+       struct mei_cl *cl;
+
+       cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
+       if (!cl)
+               return NULL;
+
+       mei_cl_init(cl, dev);
+
+       return cl;
+}
+
+
+
+/**
+ * mei_disconnect_host_client - sends disconnect message to fw from host client.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
+{
+       int rets, err;
+       long timeout = 15;      /* 15 seconds */
+       struct mei_cl_cb *cb;
+
+       if (!dev || !cl)
+               return -ENODEV;
+
+       if (cl->state != MEI_FILE_DISCONNECTING)
+               return 0;
+
+       cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+       if (!cb)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&cb->cb_list);
+       cb->file_private = cl;
+       cb->major_file_operations = MEI_CLOSE;
+       if (dev->mei_host_buffer_is_empty) {
+               dev->mei_host_buffer_is_empty = false;
+               if (mei_disconnect(dev, cl)) {
+                       rets = -ENODEV;
+                       dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n");
+                       goto free;
+               }
+               mdelay(10); /* Wait for hardware disconnection ready */
+               list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list);
+       } else {
+               dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
+               list_add_tail(&cb->cb_list,
+                               &dev->ctrl_wr_list.mei_cb.cb_list);
+       }
+       mutex_unlock(&dev->device_lock);
+
+       err = wait_event_timeout(dev->wait_recvd_msg,
+                (MEI_FILE_DISCONNECTED == cl->state),
+                timeout * HZ);
+
+       mutex_lock(&dev->device_lock);
+       if (MEI_FILE_DISCONNECTED == cl->state) {
+               rets = 0;
+               dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
+       } else {
+               rets = -ENODEV;
+               if (MEI_FILE_DISCONNECTED != cl->state)
+                       dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
+
+               if (err)
+                       dev_dbg(&dev->pdev->dev,
+                                       "wait failed disconnect err=%08x\n",
+                                       err);
+
+               dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
+       }
+
+       mei_io_list_flush(&dev->ctrl_rd_list, cl);
+       mei_io_list_flush(&dev->ctrl_wr_list, cl);
+free:
+       mei_free_cb_private(cb);
+       return rets;
+}
+
+/**
+ * mei_remove_client_from_file_list -
+ *     removes file private data from device file list
+ *
+ * @dev: the device structure
+ * @host_client_id: host client id to be removed
+ */
+void mei_remove_client_from_file_list(struct mei_device *dev,
+                                      u8 host_client_id)
+{
+       struct mei_cl *cl_pos = NULL;
+       struct mei_cl *cl_next = NULL;
+       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+               if (host_client_id == cl_pos->host_client_id) {
+                       dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
+                                       cl_pos->host_client_id,
+                                       cl_pos->me_client_id);
+                       list_del_init(&cl_pos->link);
+                       break;
+               }
+       }
+}
diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c
new file mode 100644 (file)
index 0000000..9a2cfaf
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/pci.h>
+#include "mei_dev.h"
+#include "mei.h"
+#include "interface.h"
+
+
+
+/**
+ * mei_set_csr_register - writes H_CSR register to the mei device,
+ * and ignores the H_IS bit for it is write-one-to-zero.
+ *
+ * @dev: the device structure
+ */
+void mei_hcsr_set(struct mei_device *dev)
+{
+       if ((dev->host_hw_state & H_IS) == H_IS)
+               dev->host_hw_state &= ~H_IS;
+       mei_reg_write(dev, H_CSR, dev->host_hw_state);
+       dev->host_hw_state = mei_hcsr_read(dev);
+}
+
+/**
+ * mei_csr_enable_interrupts - enables mei device interrupts
+ *
+ * @dev: the device structure
+ */
+void mei_enable_interrupts(struct mei_device *dev)
+{
+       dev->host_hw_state |= H_IE;
+       mei_hcsr_set(dev);
+}
+
+/**
+ * mei_csr_disable_interrupts - disables mei device interrupts
+ *
+ * @dev: the device structure
+ */
+void mei_disable_interrupts(struct mei_device *dev)
+{
+       dev->host_hw_state &= ~H_IE;
+       mei_hcsr_set(dev);
+}
+
+/**
+ * _host_get_filled_slots - gets number of device filled buffer slots
+ *
+ * @device: the device structure
+ *
+ * returns number of filled slots
+ */
+static unsigned char _host_get_filled_slots(const struct mei_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);
+}
+
+/**
+ * mei_host_buffer_is_empty - checks if host buffer is empty.
+ *
+ * @dev: the device structure
+ *
+ * returns 1 if empty, 0 - otherwise.
+ */
+int mei_host_buffer_is_empty(struct mei_device *dev)
+{
+       unsigned char filled_slots;
+
+       dev->host_hw_state = mei_hcsr_read(dev);
+       filled_slots = _host_get_filled_slots(dev);
+
+       if (filled_slots == 0)
+               return 1;
+
+       return 0;
+}
+
+/**
+ * mei_count_empty_write_slots - counts write empty slots.
+ *
+ * @dev: the device structure
+ *
+ * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
+ */
+int mei_count_empty_write_slots(struct mei_device *dev)
+{
+       unsigned char buffer_depth, filled_slots, empty_slots;
+
+       dev->host_hw_state = mei_hcsr_read(dev);
+       buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
+       filled_slots = _host_get_filled_slots(dev);
+       empty_slots = buffer_depth - filled_slots;
+
+       /* check for overflow */
+       if (filled_slots > buffer_depth)
+               return -EOVERFLOW;
+
+       return empty_slots;
+}
+
+/**
+ * mei_write_message - writes a message to mei device.
+ *
+ * @dev: the device structure
+ * @header: header of message
+ * @write_buffer: message buffer will be written
+ * @write_length: message size will be written
+ *
+ * This function returns -EIO if write has failed
+ */
+int mei_write_message(struct mei_device *dev,
+                     struct mei_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 = mei_hcsr_read(dev);
+
+       dev_dbg(&dev->pdev->dev,
+                       "host_hw_state = 0x%08x.\n",
+                       dev->host_hw_state);
+
+       dev_dbg(&dev->pdev->dev,
+                       "mei_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;
+       dev_dbg(&dev->pdev->dev,
+                       "filled = %hu, empty = %hu.\n",
+                       filled_slots, empty_slots);
+
+       dw_to_write = ((write_length + 3) / 4);
+
+       if (dw_to_write > empty_slots)
+               return -EIO;
+
+       mei_reg_write(dev, H_CB_WW, *((u32 *) header));
+
+       while (write_length >= 4) {
+               mei_reg_write(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);
+               mei_reg_write(dev, H_CB_WW, temp_msg);
+       }
+
+       dev->host_hw_state |= H_IG;
+       mei_hcsr_set(dev);
+       dev->me_hw_state = mei_mecsr_read(dev);
+       if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
+               return -EIO;
+
+       return 0;
+}
+
+/**
+ * mei_count_full_read_slots - counts read full slots.
+ *
+ * @dev: the device structure
+ *
+ * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
+ */
+int mei_count_full_read_slots(struct mei_device *dev)
+{
+       char read_ptr, write_ptr;
+       unsigned char buffer_depth, filled_slots;
+
+       dev->me_hw_state = mei_mecsr_read(dev);
+       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);
+
+       /* check for overflow */
+       if (filled_slots > buffer_depth)
+               return -EOVERFLOW;
+
+       dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
+       return (int)filled_slots;
+}
+
+/**
+ * mei_read_slots - reads a message from mei device.
+ *
+ * @dev: the device structure
+ * @buffer: message buffer will be written
+ * @buffer_length: message size will be read
+ */
+void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
+                   unsigned long buffer_length)
+{
+       u32 *reg_buf = (u32 *)buffer;
+
+       for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
+               *reg_buf++ = mei_mecbrw_read(dev);
+
+       if (buffer_length > 0) {
+               u32 reg = mei_mecbrw_read(dev);
+               memcpy(reg_buf, &reg, buffer_length);
+       }
+
+       dev->host_hw_state |= H_IG;
+       mei_hcsr_set(dev);
+}
+
+/**
+ * mei_flow_ctrl_creds - checks flow_control credentials.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
+ *     -ENOENT if mei_cl is not present
+ *     -EINVAL if single_recv_buf == 0
+ */
+int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
+{
+       int i;
+
+       if (!dev->me_clients_num)
+               return 0;
+
+       if (cl->mei_flow_ctrl_creds > 0)
+               return 1;
+
+       for (i = 0; i < dev->me_clients_num; i++) {
+               struct mei_me_client  *me_cl = &dev->me_clients[i];
+               if (me_cl->client_id == cl->me_client_id) {
+                       if (me_cl->mei_flow_ctrl_creds) {
+                               if (WARN_ON(me_cl->props.single_recv_buf == 0))
+                                       return -EINVAL;
+                               return 1;
+                       } else {
+                               return 0;
+                       }
+               }
+       }
+       return -ENOENT;
+}
+
+/**
+ * mei_flow_ctrl_reduce - reduces flow_control.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ * @returns
+ *     0 on success
+ *     -ENOENT when me client is not found
+ *     -EINVAL when ctrl credits are <= 0
+ */
+int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
+{
+       int i;
+
+       if (!dev->me_clients_num)
+               return -ENOENT;
+
+       for (i = 0; i < dev->me_clients_num; i++) {
+               struct mei_me_client  *me_cl = &dev->me_clients[i];
+               if (me_cl->client_id == cl->me_client_id) {
+                       if (me_cl->props.single_recv_buf != 0) {
+                               if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
+                                       return -EINVAL;
+                               dev->me_clients[i].mei_flow_ctrl_creds--;
+                       } else {
+                               if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+                                       return -EINVAL;
+                               cl->mei_flow_ctrl_creds--;
+                       }
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+/**
+ * mei_send_flow_control - sends flow control to fw.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
+{
+       struct mei_msg_hdr *mei_hdr;
+       struct hbm_flow_control *mei_flow_control;
+
+       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+       mei_hdr->host_addr = 0;
+       mei_hdr->me_addr = 0;
+       mei_hdr->length = sizeof(struct hbm_flow_control);
+       mei_hdr->msg_complete = 1;
+       mei_hdr->reserved = 0;
+
+       mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
+       memset(mei_flow_control, 0, sizeof(*mei_flow_control));
+       mei_flow_control->host_addr = cl->host_client_id;
+       mei_flow_control->me_addr = cl->me_client_id;
+       mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD;
+       memset(mei_flow_control->reserved, 0,
+                       sizeof(mei_flow_control->reserved));
+       dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
+               cl->host_client_id, cl->me_client_id);
+
+       return mei_write_message(dev, mei_hdr,
+                               (unsigned char *) mei_flow_control,
+                               sizeof(struct hbm_flow_control));
+}
+
+/**
+ * mei_other_client_is_connecting - checks if other
+ *    client with the same client id is connected.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * returns 1 if other client is connected, 0 - otherwise.
+ */
+int mei_other_client_is_connecting(struct mei_device *dev,
+                               struct mei_cl *cl)
+{
+       struct mei_cl *cl_pos = NULL;
+       struct mei_cl *cl_next = NULL;
+
+       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+               if ((cl_pos->state == MEI_FILE_CONNECTING) &&
+                       (cl_pos != cl) &&
+                       cl->me_client_id == cl_pos->me_client_id)
+                       return 1;
+
+       }
+       return 0;
+}
+
+/**
+ * mei_disconnect - sends disconnect message to fw.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
+{
+       struct mei_msg_hdr *mei_hdr;
+       struct hbm_client_disconnect_request *mei_cli_disconnect;
+
+       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+       mei_hdr->host_addr = 0;
+       mei_hdr->me_addr = 0;
+       mei_hdr->length = sizeof(struct hbm_client_disconnect_request);
+       mei_hdr->msg_complete = 1;
+       mei_hdr->reserved = 0;
+
+       mei_cli_disconnect =
+           (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
+       memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect));
+       mei_cli_disconnect->host_addr = cl->host_client_id;
+       mei_cli_disconnect->me_addr = cl->me_client_id;
+       mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
+       mei_cli_disconnect->reserved[0] = 0;
+
+       return mei_write_message(dev, mei_hdr,
+                               (unsigned char *) mei_cli_disconnect,
+                               sizeof(struct hbm_client_disconnect_request));
+}
+
+/**
+ * mei_connect - sends connect message to fw.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_connect(struct mei_device *dev, struct mei_cl *cl)
+{
+       struct mei_msg_hdr *mei_hdr;
+       struct hbm_client_connect_request *mei_cli_connect;
+
+       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+       mei_hdr->host_addr = 0;
+       mei_hdr->me_addr = 0;
+       mei_hdr->length = sizeof(struct hbm_client_connect_request);
+       mei_hdr->msg_complete = 1;
+       mei_hdr->reserved = 0;
+
+       mei_cli_connect =
+           (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
+       mei_cli_connect->host_addr = cl->host_client_id;
+       mei_cli_connect->me_addr = cl->me_client_id;
+       mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
+       mei_cli_connect->reserved = 0;
+
+       return mei_write_message(dev, mei_hdr,
+                               (unsigned char *) mei_cli_connect,
+                               sizeof(struct hbm_client_connect_request));
+}
diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h
new file mode 100644 (file)
index 0000000..0d00435
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+
+
+#ifndef _MEI_INTERFACE_H_
+#define _MEI_INTERFACE_H_
+
+#include "mei.h"
+#include "mei_dev.h"
+
+
+#define AMT_WD_DEFAULT_TIMEOUT 120     /* seconds */
+#define AMT_WD_MIN_TIMEOUT 120 /* seconds */
+#define AMT_WD_MAX_TIMEOUT 65535       /* seconds */
+
+#define MEI_WATCHDOG_DATA_SIZE         16
+#define MEI_START_WD_DATA_SIZE         20
+#define MEI_WD_PARAMS_SIZE             4
+
+
+void mei_read_slots(struct mei_device *dev,
+                    unsigned char *buffer,
+                    unsigned long buffer_length);
+
+int mei_write_message(struct mei_device *dev,
+                            struct mei_msg_hdr *header,
+                            unsigned char *write_buffer,
+                            unsigned long write_length);
+
+int mei_host_buffer_is_empty(struct mei_device *dev);
+
+int mei_count_full_read_slots(struct mei_device *dev);
+
+int mei_count_empty_write_slots(struct mei_device *dev);
+
+int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
+
+int mei_wd_send(struct mei_device *dev);
+int mei_wd_stop(struct mei_device *dev, bool preserve);
+int mei_wd_host_init(struct mei_device *dev);
+/*
+ * mei_watchdog_register  - Registering watchdog interface
+ *   once we got connection to the WD Client
+ * @dev - mei device
+ */
+void mei_watchdog_register(struct mei_device *dev);
+/*
+ * mei_watchdog_unregister  - Unregistering watchdog interface
+ * @dev - mei device
+ */
+void mei_watchdog_unregister(struct mei_device *dev);
+
+int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl);
+
+int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl);
+
+int mei_disconnect(struct mei_device *dev, struct mei_cl *cl);
+int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl);
+int mei_connect(struct mei_device *dev, struct mei_cl *cl);
+
+#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
new file mode 100644 (file)
index 0000000..2007d24
--- /dev/null
@@ -0,0 +1,1590 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/jiffies.h>
+
+#include "mei_dev.h"
+#include "mei.h"
+#include "hw.h"
+#include "interface.h"
+
+
+/**
+ * mei_interrupt_quick_handler - The ISR of the MEI device
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ */
+irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
+{
+       struct mei_device *dev = (struct mei_device *) dev_id;
+       u32 csr_reg = mei_hcsr_read(dev);
+
+       if ((csr_reg & H_IS) != H_IS)
+               return IRQ_NONE;
+
+       /* clear H_IS bit in H_CSR */
+       mei_reg_write(dev, H_CSR, csr_reg);
+
+       return IRQ_WAKE_THREAD;
+}
+
+/**
+ * _mei_cmpl - processes completed operation.
+ *
+ * @cl: private data of the file object.
+ * @cb_pos: callback block.
+ */
+static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
+{
+       if (cb_pos->major_file_operations == MEI_WRITE) {
+               mei_free_cb_private(cb_pos);
+               cb_pos = NULL;
+               cl->writing_state = MEI_WRITE_COMPLETE;
+               if (waitqueue_active(&cl->tx_wait))
+                       wake_up_interruptible(&cl->tx_wait);
+
+       } else if (cb_pos->major_file_operations == MEI_READ &&
+                       MEI_READING == cl->reading_state) {
+               cl->reading_state = MEI_READ_COMPLETE;
+               if (waitqueue_active(&cl->rx_wait))
+                       wake_up_interruptible(&cl->rx_wait);
+
+       }
+}
+
+/**
+ * _mei_cmpl_iamthif - processes completed iamthif operation.
+ *
+ * @dev: the device structure.
+ * @cb_pos: callback block.
+ */
+static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos)
+{
+       if (dev->iamthif_canceled != 1) {
+               dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
+               dev->iamthif_stall_timer = 0;
+               memcpy(cb_pos->response_buffer.data,
+                               dev->iamthif_msg_buf,
+                               dev->iamthif_msg_buf_index);
+               list_add_tail(&cb_pos->cb_list,
+                               &dev->amthi_read_complete_list.mei_cb.cb_list);
+               dev_dbg(&dev->pdev->dev, "amthi read completed.\n");
+               dev->iamthif_timer = jiffies;
+               dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
+                               dev->iamthif_timer);
+       } else {
+               mei_run_next_iamthif_cmd(dev);
+       }
+
+       dev_dbg(&dev->pdev->dev, "completing amthi call back.\n");
+       wake_up_interruptible(&dev->iamthif_cl.wait);
+}
+
+
+/**
+ * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to
+ * handle the read amthi message data processing.
+ *
+ * @complete_list: An instance of our list structure
+ * @dev: the device structure
+ * @mei_hdr: header of amthi message
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list,
+               struct mei_device *dev,
+               struct mei_msg_hdr *mei_hdr)
+{
+       struct mei_cl *cl;
+       struct mei_cl_cb *cb;
+       unsigned char *buffer;
+
+       BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
+       BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
+
+       buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
+       BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
+
+       mei_read_slots(dev, buffer, mei_hdr->length);
+
+       dev->iamthif_msg_buf_index += mei_hdr->length;
+
+       if (!mei_hdr->msg_complete)
+               return 0;
+
+       dev_dbg(&dev->pdev->dev,
+                       "amthi_message_buffer_index =%d\n",
+                       mei_hdr->length);
+
+       dev_dbg(&dev->pdev->dev, "completed amthi read.\n ");
+       if (!dev->iamthif_current_cb)
+               return -ENODEV;
+
+       cb = dev->iamthif_current_cb;
+       dev->iamthif_current_cb = NULL;
+
+       cl = (struct mei_cl *)cb->file_private;
+       if (!cl)
+               return -ENODEV;
+
+       dev->iamthif_stall_timer = 0;
+       cb->information =       dev->iamthif_msg_buf_index;
+       cb->read_time = jiffies;
+       if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) {
+               /* found the iamthif cb */
+               dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n ");
+               dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n ");
+               list_add_tail(&cb->cb_list,
+                                               &complete_list->mei_cb.cb_list);
+       }
+       return 0;
+}
+
+/**
+ * _mei_irq_thread_state_ok - checks if mei header matches file private data
+ *
+ * @cl: private data of the file object
+ * @mei_hdr: header of mei client message
+ *
+ * returns !=0 if matches, 0 if no match.
+ */
+static int _mei_irq_thread_state_ok(struct mei_cl *cl,
+                               struct mei_msg_hdr *mei_hdr)
+{
+       return (cl->host_client_id == mei_hdr->host_addr &&
+               cl->me_client_id == mei_hdr->me_addr &&
+               cl->state == MEI_FILE_CONNECTED &&
+               MEI_READ_COMPLETE != cl->reading_state);
+}
+
+/**
+ * mei_irq_thread_read_client_message - bottom half read routine after ISR to
+ * handle the read mei client message data processing.
+ *
+ * @complete_list: An instance of our list structure
+ * @dev: the device structure
+ * @mei_hdr: header of mei client message
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
+               struct mei_device *dev,
+               struct mei_msg_hdr *mei_hdr)
+{
+       struct mei_cl *cl;
+       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+       unsigned char *buffer = NULL;
+
+       dev_dbg(&dev->pdev->dev, "start client msg\n");
+       if (list_empty(&dev->read_list.mei_cb.cb_list))
+               goto quit;
+
+       list_for_each_entry_safe(cb_pos, cb_next,
+                       &dev->read_list.mei_cb.cb_list, cb_list) {
+               cl = (struct mei_cl *)cb_pos->file_private;
+               if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
+                       cl->reading_state = MEI_READING;
+                       buffer = cb_pos->response_buffer.data + cb_pos->information;
+
+                       if (cb_pos->response_buffer.size <
+                                       mei_hdr->length + cb_pos->information) {
+                               dev_dbg(&dev->pdev->dev, "message overflow.\n");
+                               list_del(&cb_pos->cb_list);
+                               return -ENOMEM;
+                       }
+                       if (buffer)
+                               mei_read_slots(dev, buffer, mei_hdr->length);
+
+                       cb_pos->information += mei_hdr->length;
+                       if (mei_hdr->msg_complete) {
+                               cl->status = 0;
+                               list_del(&cb_pos->cb_list);
+                               dev_dbg(&dev->pdev->dev,
+                                       "completed read host client = %d,"
+                                       "ME client = %d, "
+                                       "data length = %lu\n",
+                                       cl->host_client_id,
+                                       cl->me_client_id,
+                                       cb_pos->information);
+
+                               *(cb_pos->response_buffer.data +
+                                       cb_pos->information) = '\0';
+                               dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n",
+                                       cb_pos->response_buffer.data);
+                               list_add_tail(&cb_pos->cb_list,
+                                       &complete_list->mei_cb.cb_list);
+                       }
+
+                       break;
+               }
+
+       }
+
+quit:
+       dev_dbg(&dev->pdev->dev, "message read\n");
+       if (!buffer) {
+               mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
+               dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
+                               *(u32 *) dev->rd_msg_buf);
+       }
+
+       return 0;
+}
+
+/**
+ * _mei_irq_thread_iamthif_read - prepares to read iamthif data.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
+{
+
+       if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
+                       + sizeof(struct hbm_flow_control))) {
+               return -EMSGSIZE;
+       }
+       *slots -= (sizeof(struct mei_msg_hdr) +
+                               sizeof(struct hbm_flow_control) + 3) / 4;
+       if (mei_send_flow_control(dev, &dev->iamthif_cl)) {
+               dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
+               return -EIO;
+       }
+
+       dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
+       dev->iamthif_state = MEI_IAMTHIF_READING;
+       dev->iamthif_flow_control_pending = false;
+       dev->iamthif_msg_buf_index = 0;
+       dev->iamthif_msg_buf_size = 0;
+       dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
+       dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
+       return 0;
+}
+
+/**
+ * _mei_irq_thread_close - processes close related operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
+                               struct mei_cl_cb *cb_pos,
+                               struct mei_cl *cl,
+                               struct mei_io_list *cmpl_list)
+{
+       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+                       sizeof(struct hbm_client_disconnect_request))) {
+               *slots -= (sizeof(struct mei_msg_hdr) +
+                       sizeof(struct hbm_client_disconnect_request) + 3) / 4;
+
+               if (mei_disconnect(dev, cl)) {
+                       cl->status = 0;
+                       cb_pos->information = 0;
+                       list_move_tail(&cb_pos->cb_list,
+                                       &cmpl_list->mei_cb.cb_list);
+                       return -EMSGSIZE;
+               } else {
+                       cl->state = MEI_FILE_DISCONNECTING;
+                       cl->status = 0;
+                       cb_pos->information = 0;
+                       list_move_tail(&cb_pos->cb_list,
+                                       &dev->ctrl_rd_list.mei_cb.cb_list);
+                       cl->timer_count = MEI_CONNECT_TIMEOUT;
+               }
+       } else {
+               /* return the cancel routine */
+               return -EBADMSG;
+       }
+
+       return 0;
+}
+
+/**
+ * is_treat_specially_client - checks if the message belongs
+ * to the file private data.
+ *
+ * @cl: private data of the file object
+ * @rs: connect response bus message
+ *
+ */
+static bool is_treat_specially_client(struct mei_cl *cl,
+               struct hbm_client_connect_response *rs)
+{
+
+       if (cl->host_client_id == rs->host_addr &&
+           cl->me_client_id == rs->me_addr) {
+               if (!rs->status) {
+                       cl->state = MEI_FILE_CONNECTED;
+                       cl->status = 0;
+
+               } else {
+                       cl->state = MEI_FILE_DISCONNECTED;
+                       cl->status = -ENODEV;
+               }
+               cl->timer_count = 0;
+
+               return true;
+       }
+       return false;
+}
+
+/**
+ * mei_client_connect_response - connects to response irq routine
+ *
+ * @dev: the device structure
+ * @rs: connect response bus message
+ */
+static void mei_client_connect_response(struct mei_device *dev,
+               struct hbm_client_connect_response *rs)
+{
+
+       struct mei_cl *cl;
+       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+
+       dev_dbg(&dev->pdev->dev,
+                       "connect_response:\n"
+                       "ME Client = %d\n"
+                       "Host Client = %d\n"
+                       "Status = %d\n",
+                       rs->me_addr,
+                       rs->host_addr,
+                       rs->status);
+
+       /* if WD or iamthif client treat specially */
+
+       if (is_treat_specially_client(&(dev->wd_cl), rs)) {
+               dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
+               mei_watchdog_register(dev);
+
+               /* next step in the state maching */
+               mei_host_init_iamthif(dev);
+               return;
+       }
+
+       if (is_treat_specially_client(&(dev->iamthif_cl), rs)) {
+               dev->iamthif_state = MEI_IAMTHIF_IDLE;
+               return;
+       }
+       list_for_each_entry_safe(cb_pos, cb_next,
+                               &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
+
+               cl = (struct mei_cl *)cb_pos->file_private;
+               if (!cl) {
+                       list_del(&cb_pos->cb_list);
+                       return;
+               }
+               if (MEI_IOCTL == cb_pos->major_file_operations) {
+                       if (is_treat_specially_client(cl, rs)) {
+                               list_del(&cb_pos->cb_list);
+                               cl->status = 0;
+                               cl->timer_count = 0;
+                               break;
+                       }
+               }
+       }
+}
+
+/**
+ * mei_client_disconnect_response - disconnects from response irq routine
+ *
+ * @dev: the device structure
+ * @rs: disconnect response bus message
+ */
+static void mei_client_disconnect_response(struct mei_device *dev,
+                                       struct hbm_client_connect_response *rs)
+{
+       struct mei_cl *cl;
+       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+
+       dev_dbg(&dev->pdev->dev,
+                       "disconnect_response:\n"
+                       "ME Client = %d\n"
+                       "Host Client = %d\n"
+                       "Status = %d\n",
+                       rs->me_addr,
+                       rs->host_addr,
+                       rs->status);
+
+       list_for_each_entry_safe(cb_pos, cb_next,
+                       &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
+               cl = (struct mei_cl *)cb_pos->file_private;
+
+               if (!cl) {
+                       list_del(&cb_pos->cb_list);
+                       return;
+               }
+
+               dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
+               if (cl->host_client_id == rs->host_addr &&
+                   cl->me_client_id == rs->me_addr) {
+
+                       list_del(&cb_pos->cb_list);
+                       if (!rs->status)
+                               cl->state = MEI_FILE_DISCONNECTED;
+
+                       cl->status = 0;
+                       cl->timer_count = 0;
+                       break;
+               }
+       }
+}
+
+/**
+ * same_flow_addr - tells if they have the same address.
+ *
+ * @file: private data of the file object.
+ * @flow: flow control.
+ *
+ * returns  !=0, same; 0,not.
+ */
+static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow)
+{
+       return (cl->host_client_id == flow->host_addr &&
+               cl->me_client_id == flow->me_addr);
+}
+
+/**
+ * add_single_flow_creds - adds single buffer credentials.
+ *
+ * @file: private data ot the file object.
+ * @flow: flow control.
+ */
+static void add_single_flow_creds(struct mei_device *dev,
+                                 struct hbm_flow_control *flow)
+{
+       struct mei_me_client *client;
+       int i;
+
+       for (i = 0; i < dev->me_clients_num; i++) {
+               client = &dev->me_clients[i];
+               if (client && flow->me_addr == client->client_id) {
+                       if (client->props.single_recv_buf) {
+                               client->mei_flow_ctrl_creds++;
+                               dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
+                                   flow->me_addr);
+                               dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
+                                   client->mei_flow_ctrl_creds);
+                       } else {
+                               BUG();  /* error in flow control */
+                       }
+               }
+       }
+}
+
+/**
+ * mei_client_flow_control_response - flow control response irq routine
+ *
+ * @dev: the device structure
+ * @flow_control: flow control response bus message
+ */
+static void mei_client_flow_control_response(struct mei_device *dev,
+               struct hbm_flow_control *flow_control)
+{
+       struct mei_cl *cl_pos = NULL;
+       struct mei_cl *cl_next = NULL;
+
+       if (!flow_control->host_addr) {
+               /* single receive buffer */
+               add_single_flow_creds(dev, flow_control);
+       } else {
+               /* normal connection */
+               list_for_each_entry_safe(cl_pos, cl_next,
+                               &dev->file_list, link) {
+                       dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n");
+
+                       dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n",
+                           cl_pos->host_client_id,
+                           cl_pos->me_client_id);
+                       dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
+                           flow_control->host_addr,
+                           flow_control->me_addr);
+                       if (same_flow_addr(cl_pos, flow_control)) {
+                               dev_dbg(&dev->pdev->dev, "recv ctrl msg for host  %d ME %d.\n",
+                                   flow_control->host_addr,
+                                   flow_control->me_addr);
+                               cl_pos->mei_flow_ctrl_creds++;
+                               dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
+                                   cl_pos->mei_flow_ctrl_creds);
+                               break;
+                       }
+               }
+       }
+}
+
+/**
+ * same_disconn_addr - tells if they have the same address
+ *
+ * @file: private data of the file object.
+ * @disconn: disconnection request.
+ *
+ * returns !=0, same; 0,not.
+ */
+static int same_disconn_addr(struct mei_cl *cl,
+                            struct hbm_client_disconnect_request *disconn)
+{
+       return (cl->host_client_id == disconn->host_addr &&
+               cl->me_client_id == disconn->me_addr);
+}
+
+/**
+ * mei_client_disconnect_request - disconnects from request irq routine
+ *
+ * @dev: the device structure.
+ * @disconnect_req: disconnect request bus message.
+ */
+static void mei_client_disconnect_request(struct mei_device *dev,
+               struct hbm_client_disconnect_request *disconnect_req)
+{
+       struct mei_msg_hdr *mei_hdr;
+       struct hbm_client_connect_response *disconnect_res;
+       struct mei_cl *cl_pos = NULL;
+       struct mei_cl *cl_next = NULL;
+
+       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+               if (same_disconn_addr(cl_pos, disconnect_req)) {
+                       dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
+                                       disconnect_req->host_addr,
+                                       disconnect_req->me_addr);
+                       cl_pos->state = MEI_FILE_DISCONNECTED;
+                       cl_pos->timer_count = 0;
+                       if (cl_pos == &dev->wd_cl) {
+                               dev->wd_due_counter = 0;
+                               dev->wd_pending = false;
+                       } else if (cl_pos == &dev->iamthif_cl)
+                               dev->iamthif_timer = 0;
+
+                       /* prepare disconnect response */
+                       mei_hdr =
+                               (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
+                       mei_hdr->host_addr = 0;
+                       mei_hdr->me_addr = 0;
+                       mei_hdr->length =
+                               sizeof(struct hbm_client_connect_response);
+                       mei_hdr->msg_complete = 1;
+                       mei_hdr->reserved = 0;
+
+                       disconnect_res =
+                               (struct hbm_client_connect_response *)
+                               &dev->ext_msg_buf[1];
+                       disconnect_res->host_addr = cl_pos->host_client_id;
+                       disconnect_res->me_addr = cl_pos->me_client_id;
+                       disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
+                       disconnect_res->status = 0;
+                       dev->extra_write_index = 2;
+                       break;
+               }
+       }
+}
+
+
+/**
+ * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
+ * handle the read bus message cmd processing.
+ *
+ * @dev: the device structure
+ * @mei_hdr: header of bus message
+ */
+static void mei_irq_thread_read_bus_message(struct mei_device *dev,
+               struct mei_msg_hdr *mei_hdr)
+{
+       struct mei_bus_message *mei_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 *host_stop_req;
+       int res;
+
+
+       /* read the message to our buffer */
+       BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
+       mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
+       mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
+
+       switch (mei_msg->hbm_cmd) {
+       case HOST_START_RES_CMD:
+               version_res = (struct hbm_host_version_response *) mei_msg;
+               if (version_res->host_version_supported) {
+                       dev->version.major_version = HBM_MAJOR_VERSION;
+                       dev->version.minor_version = HBM_MINOR_VERSION;
+                       if (dev->mei_state == MEI_INIT_CLIENTS &&
+                           dev->init_clients_state == MEI_START_MESSAGE) {
+                               dev->init_clients_timer = 0;
+                               mei_host_enum_clients_message(dev);
+                       } else {
+                               dev->recvd_msg = false;
+                               dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
+                               mei_reset(dev, 1);
+                               return;
+                       }
+               } else {
+                       dev->version = version_res->me_max_version;
+                       /* send stop message */
+                       mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
+                       mei_hdr->host_addr = 0;
+                       mei_hdr->me_addr = 0;
+                       mei_hdr->length = sizeof(struct hbm_host_stop_request);
+                       mei_hdr->msg_complete = 1;
+                       mei_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->hbm_cmd = HOST_STOP_REQ_CMD;
+                       host_stop_req->reason = DRIVER_STOP_REQUEST;
+                       mei_write_message(dev, mei_hdr,
+                                          (unsigned char *) (host_stop_req),
+                                          mei_hdr->length);
+                       dev_dbg(&dev->pdev->dev, "version mismatch.\n");
+                       return;
+               }
+
+               dev->recvd_msg = true;
+               dev_dbg(&dev->pdev->dev, "host start response message received.\n");
+               break;
+
+       case CLIENT_CONNECT_RES_CMD:
+               connect_res =
+                       (struct hbm_client_connect_response *) mei_msg;
+               mei_client_connect_response(dev, connect_res);
+               dev_dbg(&dev->pdev->dev, "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 *) mei_msg;
+               mei_client_disconnect_response(dev, disconnect_res);
+               dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
+               wake_up(&dev->wait_recvd_msg);
+               break;
+
+       case MEI_FLOW_CONTROL_CMD:
+               flow_control = (struct hbm_flow_control *) mei_msg;
+               mei_client_flow_control_response(dev, flow_control);
+               dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
+               break;
+
+       case HOST_CLIENT_PROPERTIES_RES_CMD:
+               props_res = (struct hbm_props_response *)mei_msg;
+               if (props_res->status || !dev->me_clients) {
+                       dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
+                       mei_reset(dev, 1);
+                       return;
+               }
+               if (dev->me_clients[dev->me_client_presentation_num]
+                                       .client_id == props_res->address) {
+
+                       dev->me_clients[dev->me_client_presentation_num].props
+                                               = props_res->client_properties;
+
+                       if (dev->mei_state == MEI_INIT_CLIENTS &&
+                           dev->init_clients_state ==
+                                       MEI_CLIENT_PROPERTIES_MESSAGE) {
+                               dev->me_client_index++;
+                               dev->me_client_presentation_num++;
+
+                               /** Send Client Properties request **/
+                               res = mei_host_client_properties(dev);
+                               if (res < 0) {
+                                       dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed");
+                                       return;
+                               } else if (!res) {
+                                       /*
+                                        * No more clients to send to.
+                                        * Clear Map for indicating now ME clients
+                                        * with associated host client
+                                        */
+                                       bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
+                                       dev->open_handle_count = 0;
+
+                                       /*
+                                        * Reserving the first three client IDs
+                                        * Client Id 0 - Reserved for MEI Bus Message communications
+                                        * Client Id 1 - Reserved for Watchdog
+                                        * Client ID 2 - Reserved for AMTHI
+                                        */
+                                       bitmap_set(dev->host_clients_map, 0, 3);
+                                       dev->mei_state = MEI_ENABLED;
+
+                                       /* if wd initialization fails, initialization the AMTHI client,
+                                        * otherwise the AMTHI client will be initialized after the WD client connect response
+                                        * will be received
+                                        */
+                                       if (mei_wd_host_init(dev))
+                                               mei_host_init_iamthif(dev);
+                               }
+
+                       } else {
+                               dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message");
+                               mei_reset(dev, 1);
+                               return;
+                       }
+               } else {
+                       dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n");
+                       mei_reset(dev, 1);
+                       return;
+               }
+               break;
+
+       case HOST_ENUM_RES_CMD:
+               enum_res = (struct hbm_host_enum_response *) mei_msg;
+               memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
+               if (dev->mei_state == MEI_INIT_CLIENTS &&
+                   dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
+                               dev->init_clients_timer = 0;
+                               dev->me_client_presentation_num = 0;
+                               dev->me_client_index = 0;
+                               mei_allocate_me_clients_storage(dev);
+                               dev->init_clients_state =
+                                       MEI_CLIENT_PROPERTIES_MESSAGE;
+                               mei_host_client_properties(dev);
+               } else {
+                       dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
+                       mei_reset(dev, 1);
+                       return;
+               }
+               break;
+
+       case HOST_STOP_RES_CMD:
+               dev->mei_state = MEI_DISABLED;
+               dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
+               mei_reset(dev, 1);
+               break;
+
+       case CLIENT_DISCONNECT_REQ_CMD:
+               /* search for client */
+               disconnect_req =
+                       (struct hbm_client_disconnect_request *) mei_msg;
+               mei_client_disconnect_request(dev, disconnect_req);
+               break;
+
+       case ME_STOP_REQ_CMD:
+               /* prepare stop request */
+               mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
+               mei_hdr->host_addr = 0;
+               mei_hdr->me_addr = 0;
+               mei_hdr->length = sizeof(struct hbm_host_stop_request);
+               mei_hdr->msg_complete = 1;
+               mei_hdr->reserved = 0;
+               host_stop_req =
+                       (struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
+               memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
+               host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
+               host_stop_req->reason = DRIVER_STOP_REQUEST;
+               host_stop_req->reserved[0] = 0;
+               host_stop_req->reserved[1] = 0;
+               dev->extra_write_index = 2;
+               break;
+
+       default:
+               BUG();
+               break;
+
+       }
+}
+
+
+/**
+ * _mei_hb_read - processes read related operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_read(struct mei_device *dev,        s32 *slots,
+                       struct mei_cl_cb *cb_pos,
+                       struct mei_cl *cl,
+                       struct mei_io_list *cmpl_list)
+{
+       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+                       sizeof(struct hbm_flow_control))) {
+               /* return the cancel routine */
+               list_del(&cb_pos->cb_list);
+               return -EBADMSG;
+       }
+
+       *slots -= (sizeof(struct mei_msg_hdr) +
+                       sizeof(struct hbm_flow_control) + 3) / 4;
+       if (mei_send_flow_control(dev, cl)) {
+               cl->status = -ENODEV;
+               cb_pos->information = 0;
+               list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list);
+               return -ENODEV;
+       }
+       list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list);
+
+       return 0;
+}
+
+
+/**
+ * _mei_irq_thread_ioctl - processes ioctl related operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
+                       struct mei_cl_cb *cb_pos,
+                       struct mei_cl *cl,
+                       struct mei_io_list *cmpl_list)
+{
+       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+                       sizeof(struct hbm_client_connect_request))) {
+               cl->state = MEI_FILE_CONNECTING;
+               *slots -= (sizeof(struct mei_msg_hdr) +
+                       sizeof(struct hbm_client_connect_request) + 3) / 4;
+               if (mei_connect(dev, cl)) {
+                       cl->status = -ENODEV;
+                       cb_pos->information = 0;
+                       list_del(&cb_pos->cb_list);
+                       return -ENODEV;
+               } else {
+                       list_move_tail(&cb_pos->cb_list,
+                               &dev->ctrl_rd_list.mei_cb.cb_list);
+                       cl->timer_count = MEI_CONNECT_TIMEOUT;
+               }
+       } else {
+               /* return the cancel routine */
+               list_del(&cb_pos->cb_list);
+               return -EBADMSG;
+       }
+
+       return 0;
+}
+
+/**
+ * _mei_irq_thread_cmpl - processes completed and no-iamthif operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_cmpl(struct mei_device *dev,        s32 *slots,
+                       struct mei_cl_cb *cb_pos,
+                       struct mei_cl *cl,
+                       struct mei_io_list *cmpl_list)
+{
+       struct mei_msg_hdr *mei_hdr;
+
+       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+                       (cb_pos->request_buffer.size -
+                       cb_pos->information))) {
+               mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+               mei_hdr->host_addr = cl->host_client_id;
+               mei_hdr->me_addr = cl->me_client_id;
+               mei_hdr->length = cb_pos->request_buffer.size -
+                                       cb_pos->information;
+               mei_hdr->msg_complete = 1;
+               mei_hdr->reserved = 0;
+               dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d"
+                       "mei_hdr->msg_complete = %d\n",
+                               cb_pos->request_buffer.size,
+                               mei_hdr->msg_complete);
+               dev_dbg(&dev->pdev->dev, "cb_pos->information  =%lu\n",
+                               cb_pos->information);
+               dev_dbg(&dev->pdev->dev, "mei_hdr->length  =%d\n",
+                               mei_hdr->length);
+               *slots -= (sizeof(struct mei_msg_hdr) +
+                               mei_hdr->length + 3) / 4;
+               if (mei_write_message(dev, mei_hdr,
+                               (unsigned char *)
+                               (cb_pos->request_buffer.data +
+                               cb_pos->information),
+                               mei_hdr->length)) {
+                       cl->status = -ENODEV;
+                       list_move_tail(&cb_pos->cb_list,
+                               &cmpl_list->mei_cb.cb_list);
+                       return -ENODEV;
+               } else {
+                       if (mei_flow_ctrl_reduce(dev, cl))
+                               return -ENODEV;
+                       cl->status = 0;
+                       cb_pos->information += mei_hdr->length;
+                       list_move_tail(&cb_pos->cb_list,
+                               &dev->write_waiting_list.mei_cb.cb_list);
+               }
+       } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
+               /* buffer is still empty */
+               mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+               mei_hdr->host_addr = cl->host_client_id;
+               mei_hdr->me_addr = cl->me_client_id;
+               mei_hdr->length =
+                       (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+               mei_hdr->msg_complete = 0;
+               mei_hdr->reserved = 0;
+
+               (*slots) -= (sizeof(struct mei_msg_hdr) +
+                               mei_hdr->length + 3) / 4;
+               if (mei_write_message(dev, mei_hdr,
+                                       (unsigned char *)
+                                       (cb_pos->request_buffer.data +
+                                       cb_pos->information),
+                                       mei_hdr->length)) {
+                       cl->status = -ENODEV;
+                       list_move_tail(&cb_pos->cb_list,
+                               &cmpl_list->mei_cb.cb_list);
+                       return -ENODEV;
+               } else {
+                       cb_pos->information += mei_hdr->length;
+                       dev_dbg(&dev->pdev->dev,
+                                       "cb_pos->request_buffer.size =%d"
+                                       " mei_hdr->msg_complete = %d\n",
+                                       cb_pos->request_buffer.size,
+                                       mei_hdr->msg_complete);
+                       dev_dbg(&dev->pdev->dev, "cb_pos->information  =%lu\n",
+                                       cb_pos->information);
+                       dev_dbg(&dev->pdev->dev, "mei_hdr->length  =%d\n",
+                                       mei_hdr->length);
+               }
+               return -EMSGSIZE;
+       } else {
+               return -EBADMSG;
+       }
+
+       return 0;
+}
+
+/**
+ * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation.
+ *
+ * @dev: the device structure.
+ * @slots: free slots.
+ * @cb_pos: callback block.
+ * @cl: private data of the file object.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots,
+                       struct mei_cl_cb *cb_pos,
+                       struct mei_cl *cl,
+                       struct mei_io_list *cmpl_list)
+{
+       struct mei_msg_hdr *mei_hdr;
+
+       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
+                       dev->iamthif_msg_buf_size -
+                       dev->iamthif_msg_buf_index)) {
+               mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+               mei_hdr->host_addr = cl->host_client_id;
+               mei_hdr->me_addr = cl->me_client_id;
+               mei_hdr->length = dev->iamthif_msg_buf_size -
+                       dev->iamthif_msg_buf_index;
+               mei_hdr->msg_complete = 1;
+               mei_hdr->reserved = 0;
+
+               *slots -= (sizeof(struct mei_msg_hdr) +
+                               mei_hdr->length + 3) / 4;
+
+               if (mei_write_message(dev, mei_hdr,
+                                       (dev->iamthif_msg_buf +
+                                       dev->iamthif_msg_buf_index),
+                                       mei_hdr->length)) {
+                       dev->iamthif_state = MEI_IAMTHIF_IDLE;
+                       cl->status = -ENODEV;
+                       list_del(&cb_pos->cb_list);
+                       return -ENODEV;
+               } else {
+                       if (mei_flow_ctrl_reduce(dev, cl))
+                               return -ENODEV;
+                       dev->iamthif_msg_buf_index += mei_hdr->length;
+                       cb_pos->information = dev->iamthif_msg_buf_index;
+                       cl->status = 0;
+                       dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
+                       dev->iamthif_flow_control_pending = true;
+                       /* save iamthif cb sent to amthi client */
+                       dev->iamthif_current_cb = cb_pos;
+                       list_move_tail(&cb_pos->cb_list,
+                               &dev->write_waiting_list.mei_cb.cb_list);
+
+               }
+       } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
+                       /* buffer is still empty */
+               mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+               mei_hdr->host_addr = cl->host_client_id;
+               mei_hdr->me_addr = cl->me_client_id;
+               mei_hdr->length =
+                       (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+               mei_hdr->msg_complete = 0;
+               mei_hdr->reserved = 0;
+
+               *slots -= (sizeof(struct mei_msg_hdr) +
+                               mei_hdr->length + 3) / 4;
+
+               if (mei_write_message(dev, mei_hdr,
+                                       (dev->iamthif_msg_buf +
+                                       dev->iamthif_msg_buf_index),
+                                       mei_hdr->length)) {
+                       cl->status = -ENODEV;
+                       list_del(&cb_pos->cb_list);
+               } else {
+                       dev->iamthif_msg_buf_index += mei_hdr->length;
+               }
+               return -EMSGSIZE;
+       } else {
+               return -EBADMSG;
+       }
+
+       return 0;
+}
+
+/**
+ * mei_irq_thread_read_handler - bottom half read routine after ISR to
+ * handle the read processing.
+ *
+ * @cmpl_list: An instance of our list structure
+ * @dev: the device structure
+ * @slots: slots to read.
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list,
+               struct mei_device *dev,
+               s32 *slots)
+{
+       struct mei_msg_hdr *mei_hdr;
+       struct mei_cl *cl_pos = NULL;
+       struct mei_cl *cl_next = NULL;
+       int ret = 0;
+
+       if (!dev->rd_msg_hdr) {
+               dev->rd_msg_hdr = mei_mecbrw_read(dev);
+               dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
+               (*slots)--;
+               dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
+       }
+       mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
+       dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length);
+
+       if (mei_hdr->reserved || !dev->rd_msg_hdr) {
+               dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
+               ret = -EBADMSG;
+               goto end;
+       }
+
+       if (mei_hdr->host_addr || mei_hdr->me_addr) {
+               list_for_each_entry_safe(cl_pos, cl_next,
+                                       &dev->file_list, link) {
+                       dev_dbg(&dev->pdev->dev,
+                                       "list_for_each_entry_safe read host"
+                                       " client = %d, ME client = %d\n",
+                                       cl_pos->host_client_id,
+                                       cl_pos->me_client_id);
+                       if (cl_pos->host_client_id == mei_hdr->host_addr &&
+                           cl_pos->me_client_id == mei_hdr->me_addr)
+                               break;
+               }
+
+               if (&cl_pos->link == &dev->file_list) {
+                       dev_dbg(&dev->pdev->dev, "corrupted message header\n");
+                       ret = -EBADMSG;
+                       goto end;
+               }
+       }
+       if (((*slots) * sizeof(u32)) < mei_hdr->length) {
+               dev_dbg(&dev->pdev->dev,
+                               "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 (!mei_hdr->host_addr) {
+               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
+               mei_irq_thread_read_bus_message(dev, mei_hdr);
+               dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
+       } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
+                  (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
+                  (dev->iamthif_state == MEI_IAMTHIF_READING)) {
+               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
+               dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
+                               mei_hdr->length);
+               ret = mei_irq_thread_read_amthi_message(cmpl_list,
+                                                       dev, mei_hdr);
+               if (ret)
+                       goto end;
+
+       } else {
+               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
+               ret = mei_irq_thread_read_client_message(cmpl_list,
+                                                        dev, mei_hdr);
+               if (ret)
+                       goto end;
+
+       }
+
+       /* reset the number of slots and header */
+       *slots = mei_count_full_read_slots(dev);
+       dev->rd_msg_hdr = 0;
+
+       if (*slots == -EOVERFLOW) {
+               /* overflow - reset */
+               dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
+               /* set the event since message has been read */
+               ret = -ERANGE;
+               goto end;
+       }
+end:
+       return ret;
+}
+
+
+/**
+ * mei_irq_thread_write_handler - bottom half write routine after
+ * ISR to handle the write processing.
+ *
+ * @cmpl_list: An instance of our list structure
+ * @dev: the device structure
+ * @slots: slots to write.
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
+               struct mei_device *dev,
+               s32 *slots)
+{
+
+       struct mei_cl *cl;
+       struct mei_cl_cb *pos = NULL, *next = NULL;
+       struct mei_io_list *list;
+       int ret;
+
+       if (!mei_host_buffer_is_empty(dev)) {
+               dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
+               return 0;
+       }
+       *slots = mei_count_empty_write_slots(dev);
+       /* complete all waiting for write CB */
+       dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
+
+       list = &dev->write_waiting_list;
+       list_for_each_entry_safe(pos, next,
+                       &list->mei_cb.cb_list, cb_list) {
+               cl = (struct mei_cl *)pos->file_private;
+               if (cl == NULL)
+                       continue;
+
+               cl->status = 0;
+               list_del(&pos->cb_list);
+               if (MEI_WRITING == cl->writing_state &&
+                  (pos->major_file_operations == MEI_WRITE) &&
+                  (cl != &dev->iamthif_cl)) {
+                       dev_dbg(&dev->pdev->dev,
+                               "MEI WRITE COMPLETE\n");
+                       cl->writing_state = MEI_WRITE_COMPLETE;
+                       list_add_tail(&pos->cb_list,
+                               &cmpl_list->mei_cb.cb_list);
+               }
+               if (cl == &dev->iamthif_cl) {
+                       dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
+                       if (dev->iamthif_flow_control_pending) {
+                               ret = _mei_irq_thread_iamthif_read(
+                                               dev, slots);
+                               if (ret)
+                                       return ret;
+                       }
+               }
+       }
+
+       if (dev->stop && !dev->wd_pending) {
+               dev->wd_stopped = true;
+               wake_up_interruptible(&dev->wait_stop_wd);
+               return 0;
+       }
+
+       if (dev->extra_write_index) {
+               dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n",
+                               dev->extra_write_index);
+               mei_write_message(dev,
+                               (struct mei_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->mei_state == MEI_ENABLED) {
+               if (dev->wd_pending &&
+                       mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
+                       if (mei_wd_send(dev))
+                               dev_dbg(&dev->pdev->dev, "wd send failed.\n");
+                       else
+                               if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
+                                       return -ENODEV;
+
+                       dev->wd_pending = false;
+
+                       if (dev->wd_timeout) {
+                               *slots -= (sizeof(struct mei_msg_hdr) +
+                                        MEI_START_WD_DATA_SIZE + 3) / 4;
+                               dev->wd_due_counter = 2;
+                       } else {
+                               *slots -= (sizeof(struct mei_msg_hdr) +
+                                        MEI_WD_PARAMS_SIZE + 3) / 4;
+                               dev->wd_due_counter = 0;
+                       }
+
+               }
+       }
+       if (dev->stop)
+               return -ENODEV;
+
+       /* complete control write list CB */
+       dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
+       list_for_each_entry_safe(pos, next,
+                               &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) {
+               cl = (struct mei_cl *) pos->file_private;
+               if (!cl) {
+                       list_del(&pos->cb_list);
+                       return -ENODEV;
+               }
+               switch (pos->major_file_operations) {
+               case MEI_CLOSE:
+                       /* send disconnect message */
+                       ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list);
+                       if (ret)
+                               return ret;
+
+                       break;
+               case MEI_READ:
+                       /* send flow control message */
+                       ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list);
+                       if (ret)
+                               return ret;
+
+                       break;
+               case MEI_IOCTL:
+                       /* connect message */
+                       if (mei_other_client_is_connecting(dev, cl))
+                               continue;
+                       ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list);
+                       if (ret)
+                               return ret;
+
+                       break;
+
+               default:
+                       BUG();
+               }
+
+       }
+       /* complete  write list CB */
+       dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
+       list_for_each_entry_safe(pos, next,
+                       &dev->write_list.mei_cb.cb_list, cb_list) {
+               cl = (struct mei_cl *)pos->file_private;
+               if (cl == NULL)
+                       continue;
+
+               if (cl != &dev->iamthif_cl) {
+                       if (!mei_flow_ctrl_creds(dev, cl)) {
+                               dev_dbg(&dev->pdev->dev,
+                                       "No flow control"
+                                   " credentials for client"
+                                   " %d, not sending.\n",
+                                   cl->host_client_id);
+                               continue;
+                       }
+                       ret = _mei_irq_thread_cmpl(dev, slots,
+                                           pos,
+                                           cl, cmpl_list);
+                       if (ret)
+                               return ret;
+
+               } else if (cl == &dev->iamthif_cl) {
+                       /* IAMTHIF IOCTL */
+                       dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n");
+                       if (!mei_flow_ctrl_creds(dev, cl)) {
+                               dev_dbg(&dev->pdev->dev,
+                                       "No flow control"
+                                   " credentials for amthi"
+                                   " client %d.\n",
+                                   cl->host_client_id);
+                               continue;
+                       }
+                       ret = _mei_irq_thread_cmpl_iamthif(dev,
+                                               slots,
+                                               pos,
+                                               cl,
+                                               cmpl_list);
+                       if (ret)
+                               return ret;
+
+               }
+
+       }
+       return 0;
+}
+
+
+
+/**
+ * mei_timer - timer function.
+ *
+ * @work: pointer to the work_struct structure
+ *
+ * NOTE: This function is called by timer interrupt work
+ */
+void mei_timer(struct work_struct *work)
+{
+       unsigned long timeout;
+       struct mei_cl *cl_pos = NULL;
+       struct mei_cl *cl_next = NULL;
+       struct list_head *amthi_complete_list = NULL;
+       struct mei_cl_cb  *cb_pos = NULL;
+       struct mei_cl_cb  *cb_next = NULL;
+
+       struct mei_device *dev = container_of(work,
+                                       struct mei_device, timer_work.work);
+
+
+       mutex_lock(&dev->device_lock);
+       if (dev->mei_state != MEI_ENABLED) {
+               if (dev->mei_state == MEI_INIT_CLIENTS) {
+                       if (dev->init_clients_timer) {
+                               if (--dev->init_clients_timer == 0) {
+                                       dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
+                                               dev->init_clients_state);
+                                       mei_reset(dev, 1);
+                               }
+                       }
+               }
+               goto out;
+       }
+       /*** connect/disconnect timeouts ***/
+       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
+               if (cl_pos->timer_count) {
+                       if (--cl_pos->timer_count == 0) {
+                               dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
+                               mei_reset(dev, 1);
+                               goto out;
+                       }
+               }
+       }
+
+       if (dev->iamthif_stall_timer) {
+               if (--dev->iamthif_stall_timer == 0) {
+                       dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
+                       mei_reset(dev, 1);
+                       dev->iamthif_msg_buf_size = 0;
+                       dev->iamthif_msg_buf_index = 0;
+                       dev->iamthif_canceled = false;
+                       dev->iamthif_ioctl = true;
+                       dev->iamthif_state = MEI_IAMTHIF_IDLE;
+                       dev->iamthif_timer = 0;
+
+                       if (dev->iamthif_current_cb)
+                               mei_free_cb_private(dev->iamthif_current_cb);
+
+                       dev->iamthif_file_object = NULL;
+                       dev->iamthif_current_cb = NULL;
+                       mei_run_next_iamthif_cmd(dev);
+               }
+       }
+
+       if (dev->iamthif_timer) {
+
+               timeout = dev->iamthif_timer +
+                               msecs_to_jiffies(IAMTHIF_READ_TIMER);
+
+               dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
+                               dev->iamthif_timer);
+               dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
+               dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
+               if (time_after(jiffies, timeout)) {
+                       /*
+                        * User didn't read the AMTHI data on time (15sec)
+                        * freeing AMTHI for other requests
+                        */
+
+                       dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
+
+                       amthi_complete_list = &dev->amthi_read_complete_list.
+                                       mei_cb.cb_list;
+
+                       list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) {
+
+                               cl_pos = cb_pos->file_object->private_data;
+
+                               /* Finding the AMTHI entry. */
+                               if (cl_pos == &dev->iamthif_cl)
+                                       list_del(&cb_pos->cb_list);
+                       }
+                       if (dev->iamthif_current_cb)
+                               mei_free_cb_private(dev->iamthif_current_cb);
+
+                       dev->iamthif_file_object->private_data = NULL;
+                       dev->iamthif_file_object = NULL;
+                       dev->iamthif_current_cb = NULL;
+                       dev->iamthif_timer = 0;
+                       mei_run_next_iamthif_cmd(dev);
+
+               }
+       }
+out:
+       schedule_delayed_work(&dev->timer_work, 2 * HZ);
+       mutex_unlock(&dev->device_lock);
+}
+
+/**
+ *  mei_interrupt_thread_handler - function called after ISR to handle the interrupt
+ * processing.
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ *
+ */
+irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
+{
+       struct mei_device *dev = (struct mei_device *) dev_id;
+       struct mei_io_list complete_list;
+       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+       struct mei_cl *cl;
+       s32 slots;
+       int rets;
+       bool  bus_message_received;
+
+
+       dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
+       /* initialize our complete list */
+       mutex_lock(&dev->device_lock);
+       mei_io_list_init(&complete_list);
+       dev->host_hw_state = mei_hcsr_read(dev);
+
+       /* Ack the interrupt here
+        * In case of MSI we don't go through the quick handler */
+       if (pci_dev_msi_enabled(dev->pdev))
+               mei_reg_write(dev, H_CSR, dev->host_hw_state);
+
+       dev->me_hw_state = mei_mecsr_read(dev);
+
+       /* check if ME wants a reset */
+       if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
+           dev->mei_state != MEI_RESETING &&
+           dev->mei_state != MEI_INITIALIZING) {
+               dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+               mei_reset(dev, 1);
+               mutex_unlock(&dev->device_lock);
+               return IRQ_HANDLED;
+       }
+
+       /*  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) {
+                       dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+                       dev->host_hw_state |= (H_IE | H_IG | H_RDY);
+                       mei_hcsr_set(dev);
+                       dev->mei_state = MEI_INIT_CLIENTS;
+                       dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
+                       /* link is established
+                        * start sending messages.
+                        */
+                       mei_host_start_message(dev);
+                       mutex_unlock(&dev->device_lock);
+                       return IRQ_HANDLED;
+               } else {
+                       dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+                       mutex_unlock(&dev->device_lock);
+                       return IRQ_HANDLED;
+               }
+       }
+       /* check slots available for reading */
+       slots = mei_count_full_read_slots(dev);
+       dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
+               slots, dev->extra_write_index);
+       while (slots > 0 && !dev->extra_write_index) {
+               dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
+                               slots, dev->extra_write_index);
+               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
+               rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
+               if (rets)
+                       goto end;
+       }
+       rets = mei_irq_thread_write_handler(&complete_list, dev, &slots);
+end:
+       dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
+       dev->host_hw_state = mei_hcsr_read(dev);
+       dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
+
+       bus_message_received = false;
+       if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
+               dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
+               bus_message_received = true;
+       }
+       mutex_unlock(&dev->device_lock);
+       if (bus_message_received) {
+               dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
+               wake_up_interruptible(&dev->wait_recvd_msg);
+               bus_message_received = false;
+       }
+       if (list_empty(&complete_list.mei_cb.cb_list))
+               return IRQ_HANDLED;
+
+
+       list_for_each_entry_safe(cb_pos, cb_next,
+                       &complete_list.mei_cb.cb_list, cb_list) {
+               cl = (struct mei_cl *)cb_pos->file_private;
+               list_del(&cb_pos->cb_list);
+               if (cl) {
+                       if (cl != &dev->iamthif_cl) {
+                               dev_dbg(&dev->pdev->dev, "completing call back.\n");
+                               _mei_cmpl(cl, cb_pos);
+                               cb_pos = NULL;
+                       } else if (cl == &dev->iamthif_cl) {
+                               _mei_cmpl_iamthif(dev, cb_pos);
+                       }
+               }
+       }
+       return IRQ_HANDLED;
+}
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c
new file mode 100644 (file)
index 0000000..0a80dc4
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+
+#include <linux/kernel.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/init.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+
+
+#include "mei_dev.h"
+#include "hw.h"
+#include "mei.h"
+#include "interface.h"
+
+
+
+/**
+ * mei_ioctl_connect_client - the connect to fw client IOCTL function
+ *
+ * @dev: the device structure
+ * @data: IOCTL connect data, input and output parameters
+ * @file: private data of the file object
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_ioctl_connect_client(struct file *file,
+                       struct mei_connect_client_data *data)
+{
+       struct mei_device *dev;
+       struct mei_cl_cb *cb;
+       struct mei_client *client;
+       struct mei_cl *cl;
+       struct mei_cl *cl_pos = NULL;
+       struct mei_cl *cl_next = NULL;
+       long timeout = CONNECT_TIMEOUT;
+       int i;
+       int err;
+       int rets;
+
+       cl = file->private_data;
+       if (WARN_ON(!cl || !cl->dev))
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
+
+
+       /* buffered ioctl cb */
+       cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+       if (!cb) {
+               rets = -ENOMEM;
+               goto end;
+       }
+       INIT_LIST_HEAD(&cb->cb_list);
+
+       cb->major_file_operations = MEI_IOCTL;
+
+       if (dev->mei_state != MEI_ENABLED) {
+               rets = -ENODEV;
+               goto end;
+       }
+       if (cl->state != MEI_FILE_INITIALIZING &&
+           cl->state != MEI_FILE_DISCONNECTED) {
+               rets = -EBUSY;
+               goto end;
+       }
+
+       /* find ME client we're trying to connect to */
+       i = mei_find_me_client_index(dev, data->in_client_uuid);
+       if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
+               cl->me_client_id = dev->me_clients[i].client_id;
+               cl->state = MEI_FILE_CONNECTING;
+       }
+
+       dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
+                       cl->me_client_id);
+       dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
+                       dev->me_clients[i].props.protocol_version);
+       dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
+                       dev->me_clients[i].props.max_msg_length);
+
+       /* if we're connecting to amthi client then we will use the
+        * existing connection
+        */
+       if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
+               dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
+               if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
+                       rets = -ENODEV;
+                       goto end;
+               }
+               clear_bit(cl->host_client_id, dev->host_clients_map);
+               list_for_each_entry_safe(cl_pos, cl_next,
+                                        &dev->file_list, link) {
+                       if (mei_cl_cmp_id(cl, cl_pos)) {
+                               dev_dbg(&dev->pdev->dev,
+                                       "remove file private data node host"
+                                   " client = %d, ME client = %d.\n",
+                                   cl_pos->host_client_id,
+                                   cl_pos->me_client_id);
+                               list_del(&cl_pos->link);
+                       }
+
+               }
+               dev_dbg(&dev->pdev->dev, "free file private data memory.\n");
+               kfree(cl);
+
+               cl = NULL;
+               file->private_data = &dev->iamthif_cl;
+
+               client = &data->out_client_properties;
+               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_cl.status;
+
+               goto end;
+       }
+
+       if (cl->state != MEI_FILE_CONNECTING) {
+               rets = -ENODEV;
+               goto end;
+       }
+
+
+       /* prepare the output buffer */
+       client = &data->out_client_properties;
+       client->max_msg_length = dev->me_clients[i].props.max_msg_length;
+       client->protocol_version = dev->me_clients[i].props.protocol_version;
+       dev_dbg(&dev->pdev->dev, "Can connect?\n");
+       if (dev->mei_host_buffer_is_empty
+           && !mei_other_client_is_connecting(dev, cl)) {
+               dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
+               dev->mei_host_buffer_is_empty = false;
+               if (mei_connect(dev, cl)) {
+                       dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
+                       rets = -ENODEV;
+                       goto end;
+               } else {
+                       dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
+                       cl->timer_count = MEI_CONNECT_TIMEOUT;
+                       cb->file_private = cl;
+                       list_add_tail(&cb->cb_list,
+                                     &dev->ctrl_rd_list.mei_cb.
+                                     cb_list);
+               }
+
+
+       } else {
+               dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
+               cb->file_private = cl;
+               dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
+               list_add_tail(&cb->cb_list,
+                             &dev->ctrl_wr_list.mei_cb.cb_list);
+       }
+       mutex_unlock(&dev->device_lock);
+       err = wait_event_timeout(dev->wait_recvd_msg,
+                       (MEI_FILE_CONNECTED == cl->state ||
+                        MEI_FILE_DISCONNECTED == cl->state),
+                       timeout * HZ);
+
+       mutex_lock(&dev->device_lock);
+       if (MEI_FILE_CONNECTED == cl->state) {
+               dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
+               rets = cl->status;
+               goto end;
+       } else {
+               dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
+                   cl->state);
+               if (!err) {
+                       dev_dbg(&dev->pdev->dev,
+                               "wait_event_interruptible_timeout failed on client"
+                               " connect message fw response message.\n");
+               }
+               rets = -EFAULT;
+
+               mei_io_list_flush(&dev->ctrl_rd_list, cl);
+               mei_io_list_flush(&dev->ctrl_wr_list, cl);
+               goto end;
+       }
+       rets = 0;
+end:
+       dev_dbg(&dev->pdev->dev, "free connect cb memory.");
+       kfree(cb);
+       return rets;
+}
+
+/**
+ * find_amthi_read_list_entry - finds a amthilist entry for current file
+ *
+ * @dev: the device structure
+ * @file: pointer to file object
+ *
+ * returns   returned a list entry on success, NULL on failure.
+ */
+struct mei_cl_cb *find_amthi_read_list_entry(
+               struct mei_device *dev,
+               struct file *file)
+{
+       struct mei_cl *cl_temp;
+       struct mei_cl_cb *pos = NULL;
+       struct mei_cl_cb *next = NULL;
+
+       list_for_each_entry_safe(pos, next,
+           &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) {
+               cl_temp = (struct mei_cl *)pos->file_private;
+               if (cl_temp && cl_temp == &dev->iamthif_cl &&
+                       pos->file_object == file)
+                       return pos;
+       }
+       return NULL;
+}
+
+/**
+ * amthi_read - read data from AMTHI client
+ *
+ * @dev: the device structure
+ * @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
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns
+ *  returned data length on success,
+ *  zero if no data to read,
+ *  negative on failure.
+ */
+int amthi_read(struct mei_device *dev, struct file *file,
+              char __user *ubuf, size_t length, loff_t *offset)
+{
+       int rets;
+       int wait_ret;
+       struct mei_cl_cb *cb = NULL;
+       struct mei_cl *cl = file->private_data;
+       unsigned long timeout;
+       int i;
+
+       /* Only Posible if we are in timeout */
+       if (!cl || cl != &dev->iamthif_cl) {
+               dev_dbg(&dev->pdev->dev, "bad file ext.\n");
+               return -ETIMEDOUT;
+       }
+
+       for (i = 0; i < dev->me_clients_num; i++) {
+               if (dev->me_clients[i].client_id ==
+                   dev->iamthif_cl.me_client_id)
+                       break;
+       }
+
+       if (i == dev->me_clients_num) {
+               dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
+               return -ENODEV;
+       }
+       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id))
+               return -ENODEV;
+
+       dev_dbg(&dev->pdev->dev, "checking amthi data\n");
+       cb = find_amthi_read_list_entry(dev, file);
+
+       /* Check for if we can block or not*/
+       if (cb == NULL && file->f_flags & O_NONBLOCK)
+               return -EAGAIN;
+
+
+       dev_dbg(&dev->pdev->dev, "waiting for amthi data\n");
+       while (cb == NULL) {
+               /* unlock the Mutex */
+               mutex_unlock(&dev->device_lock);
+
+               wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
+                       (cb = find_amthi_read_list_entry(dev, file)));
+
+               if (wait_ret)
+                       return -ERESTARTSYS;
+
+               dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
+
+               /* Locking again the Mutex */
+               mutex_lock(&dev->device_lock);
+       }
+
+
+       dev_dbg(&dev->pdev->dev, "Got amthi data\n");
+       dev->iamthif_timer = 0;
+
+       if (cb) {
+               timeout = cb->read_time +
+                                       msecs_to_jiffies(IAMTHIF_READ_TIMER);
+               dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
+                               timeout);
+
+               if  (time_after(jiffies, timeout)) {
+                       dev_dbg(&dev->pdev->dev, "amthi Time out\n");
+                       /* 15 sec for the message has expired */
+                       list_del(&cb->cb_list);
+                       rets = -ETIMEDOUT;
+                       goto free;
+               }
+       }
+       /* if the whole message will fit remove it from the list */
+       if (cb->information >= *offset && length >= (cb->information - *offset))
+               list_del(&cb->cb_list);
+       else if (cb->information > 0 && cb->information <= *offset) {
+               /* end of the message has been reached */
+               list_del(&cb->cb_list);
+               rets = 0;
+               goto free;
+       }
+               /* else means that not full buffer will be read and do not
+                * remove message from deletion list
+                */
+
+       dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n",
+           cb->response_buffer.size);
+       dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n",
+           cb->information);
+
+       /* length is being turncated to PAGE_SIZE, however,
+        * the information may be longer */
+       length = min_t(size_t, length, (cb->information - *offset));
+
+       if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
+               rets = -EFAULT;
+       else {
+               rets = length;
+               if ((*offset + length) < cb->information) {
+                       *offset += length;
+                       goto out;
+               }
+       }
+free:
+       dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n");
+       *offset = 0;
+       mei_free_cb_private(cb);
+out:
+       return rets;
+}
+
+/**
+ * mei_start_read - the start read client message function.
+ *
+ * @dev: the device structure
+ * @if_num:  minor number
+ * @cl: private data of the file object
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
+{
+       struct mei_cl_cb *cb;
+       int rets = 0;
+       int i;
+
+       if (cl->state != MEI_FILE_CONNECTED)
+               return -ENODEV;
+
+       if (dev->mei_state != MEI_ENABLED)
+               return -ENODEV;
+
+       dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
+       if (cl->read_pending || cl->read_cb) {
+               dev_dbg(&dev->pdev->dev, "read is pending.\n");
+               return -EBUSY;
+       }
+
+       cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+       if (!cb)
+               return -ENOMEM;
+
+       dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
+               cl->host_client_id, cl->me_client_id);
+
+       for (i = 0; i < dev->me_clients_num; i++) {
+               if (dev->me_clients[i].client_id == cl->me_client_id)
+                       break;
+
+       }
+
+       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
+               rets = -ENODEV;
+               goto unlock;
+       }
+
+       if (i == dev->me_clients_num) {
+               rets = -ENODEV;
+               goto unlock;
+       }
+
+       cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
+       cb->response_buffer.data =
+                       kmalloc(cb->response_buffer.size, GFP_KERNEL);
+       if (!cb->response_buffer.data) {
+               rets = -ENOMEM;
+               goto unlock;
+       }
+       dev_dbg(&dev->pdev->dev, "allocation call back data success.\n");
+       cb->major_file_operations = MEI_READ;
+       /* make sure information is zero before we start */
+       cb->information = 0;
+       cb->file_private = (void *) cl;
+       cl->read_cb = cb;
+       if (dev->mei_host_buffer_is_empty) {
+               dev->mei_host_buffer_is_empty = false;
+               if (mei_send_flow_control(dev, cl)) {
+                       rets = -ENODEV;
+                       goto unlock;
+               }
+               list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list);
+       } else {
+               list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list);
+       }
+       return rets;
+unlock:
+       mei_free_cb_private(cb);
+       return rets;
+}
+
+/**
+ * amthi_write - write iamthif data to amthi client
+ *
+ * @dev: the device structure
+ * @cb: mei call back struct
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
+{
+       struct mei_msg_hdr mei_hdr;
+       int ret;
+
+       if (!dev || !cb)
+               return -ENODEV;
+
+       dev_dbg(&dev->pdev->dev, "write data to amthi client.\n");
+
+       dev->iamthif_state = MEI_IAMTHIF_WRITING;
+       dev->iamthif_current_cb = cb;
+       dev->iamthif_file_object = cb->file_object;
+       dev->iamthif_canceled = false;
+       dev->iamthif_ioctl = true;
+       dev->iamthif_msg_buf_size = cb->request_buffer.size;
+       memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
+              cb->request_buffer.size);
+
+       ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl);
+       if (ret < 0)
+               return ret;
+
+       if (ret && dev->mei_host_buffer_is_empty) {
+               ret = 0;
+               dev->mei_host_buffer_is_empty = false;
+               if (cb->request_buffer.size >
+                       (((dev->host_hw_state & H_CBD) >> 24) * sizeof(u32))
+                               -sizeof(struct mei_msg_hdr)) {
+                       mei_hdr.length =
+                           (((dev->host_hw_state & H_CBD) >> 24) *
+                           sizeof(u32)) - sizeof(struct mei_msg_hdr);
+                       mei_hdr.msg_complete = 0;
+               } else {
+                       mei_hdr.length = cb->request_buffer.size;
+                       mei_hdr.msg_complete = 1;
+               }
+
+               mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
+               mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
+               mei_hdr.reserved = 0;
+               dev->iamthif_msg_buf_index += mei_hdr.length;
+               if (mei_write_message(dev, &mei_hdr,
+                                       (unsigned char *)(dev->iamthif_msg_buf),
+                                       mei_hdr.length))
+                       return -ENODEV;
+
+               if (mei_hdr.msg_complete) {
+                       if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
+                               return -ENODEV;
+                       dev->iamthif_flow_control_pending = true;
+                       dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
+                       dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
+                       dev->iamthif_current_cb = cb;
+                       dev->iamthif_file_object = cb->file_object;
+                       list_add_tail(&cb->cb_list,
+                                     &dev->write_waiting_list.mei_cb.cb_list);
+               } else {
+                       dev_dbg(&dev->pdev->dev, "message does not complete, "
+                                       "so add amthi cb to write list.\n");
+                       list_add_tail(&cb->cb_list,
+                                     &dev->write_list.mei_cb.cb_list);
+               }
+       } else {
+               if (!(dev->mei_host_buffer_is_empty))
+                       dev_dbg(&dev->pdev->dev, "host buffer is not empty");
+
+               dev_dbg(&dev->pdev->dev, "No flow control credentials, "
+                               "so add iamthif cb to write list.\n");
+               list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list);
+       }
+       return 0;
+}
+
+/**
+ * iamthif_ioctl_send_msg - send cmd data to amthi client
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success, <0 on failure.
+ */
+void mei_run_next_iamthif_cmd(struct mei_device *dev)
+{
+       struct mei_cl *cl_tmp;
+       struct mei_cl_cb *pos = NULL;
+       struct mei_cl_cb *next = NULL;
+       int status;
+
+       if (!dev)
+               return;
+
+       dev->iamthif_msg_buf_size = 0;
+       dev->iamthif_msg_buf_index = 0;
+       dev->iamthif_canceled = false;
+       dev->iamthif_ioctl = true;
+       dev->iamthif_state = MEI_IAMTHIF_IDLE;
+       dev->iamthif_timer = 0;
+       dev->iamthif_file_object = NULL;
+
+       dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n");
+
+       list_for_each_entry_safe(pos, next,
+                       &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) {
+               list_del(&pos->cb_list);
+               cl_tmp = (struct mei_cl *)pos->file_private;
+
+               if (cl_tmp && cl_tmp == &dev->iamthif_cl) {
+                       status = amthi_write(dev, pos);
+                       if (status) {
+                               dev_dbg(&dev->pdev->dev,
+                                       "amthi write failed status = %d\n",
+                                               status);
+                               return;
+                       }
+                       break;
+               }
+       }
+}
+
+/**
+ * mei_free_cb_private - free mei_cb_private related memory
+ *
+ * @cb: mei callback struct
+ */
+void mei_free_cb_private(struct mei_cl_cb *cb)
+{
+       if (cb == NULL)
+               return;
+
+       kfree(cb->request_buffer.data);
+       kfree(cb->response_buffer.data);
+       kfree(cb);
+}
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
new file mode 100644 (file)
index 0000000..20f80df
--- /dev/null
@@ -0,0 +1,1230 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/device.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/poll.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/compat.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+
+#include "mei_dev.h"
+#include "mei.h"
+#include "interface.h"
+
+static const char mei_driver_name[] = "mei";
+
+/* The device pointer */
+/* Currently this driver works as long as there is only a single AMT device. */
+struct pci_dev *mei_device;
+
+/* mei_pci_tbl - PCI Device ID Table */
+static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
+
+       /* required last entry */
+       {0, }
+};
+
+MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
+
+static DEFINE_MUTEX(mei_mutex);
+
+
+/**
+ * mei_clear_list - removes all callbacks associated with file
+ *             from mei_cb_list
+ *
+ * @dev: device structure.
+ * @file: file structure
+ * @mei_cb_list: callbacks list
+ *
+ * mei_clear_list is called to clear resources associated with file
+ * when application calls close function or Ctrl-C was pressed
+ *
+ * returns true if callback removed from the list, false otherwise
+ */
+static bool mei_clear_list(struct mei_device *dev,
+               struct file *file, struct list_head *mei_cb_list)
+{
+       struct mei_cl_cb *cb_pos = NULL;
+       struct mei_cl_cb *cb_next = NULL;
+       struct file *file_temp;
+       bool removed = false;
+
+       /* list all list member */
+       list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) {
+               file_temp = (struct file *)cb_pos->file_object;
+               /* check if list member associated with a file */
+               if (file_temp == file) {
+                       /* remove member from the list */
+                       list_del(&cb_pos->cb_list);
+                       /* check if cb equal to current iamthif cb */
+                       if (dev->iamthif_current_cb == cb_pos) {
+                               dev->iamthif_current_cb = NULL;
+                               /* send flow control to iamthif client */
+                               mei_send_flow_control(dev, &dev->iamthif_cl);
+                       }
+                       /* free all allocated buffers */
+                       mei_free_cb_private(cb_pos);
+                       cb_pos = NULL;
+                       removed = true;
+               }
+       }
+       return removed;
+}
+
+/**
+ * mei_clear_lists - removes all callbacks associated with file
+ *
+ * @dev: device structure
+ * @file: file structure
+ *
+ * mei_clear_lists is called to clear resources associated with file
+ * when application calls close function or Ctrl-C was pressed
+ *
+ * returns true if callback removed from the list, false otherwise
+ */
+static bool mei_clear_lists(struct mei_device *dev, struct file *file)
+{
+       bool removed = false;
+
+       /* remove callbacks associated with a file */
+       mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list);
+       if (mei_clear_list(dev, file,
+                           &dev->amthi_read_complete_list.mei_cb.cb_list))
+               removed = true;
+
+       mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list);
+
+       if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list))
+               removed = true;
+
+       if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list))
+               removed = true;
+
+       if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list))
+               removed = true;
+
+       /* check if iamthif_current_cb not NULL */
+       if (dev->iamthif_current_cb && !removed) {
+               /* check file and iamthif current cb association */
+               if (dev->iamthif_current_cb->file_object == file) {
+                       /* remove cb */
+                       mei_free_cb_private(dev->iamthif_current_cb);
+                       dev->iamthif_current_cb = NULL;
+                       removed = true;
+               }
+       }
+       return removed;
+}
+/**
+ * find_read_list_entry - find read list entry
+ *
+ * @dev: device structure
+ * @file: pointer to file structure
+ *
+ * returns cb on success, NULL on error
+ */
+static struct mei_cl_cb *find_read_list_entry(
+               struct mei_device *dev,
+               struct mei_cl *cl)
+{
+       struct mei_cl_cb *pos = NULL;
+       struct mei_cl_cb *next = NULL;
+
+       dev_dbg(&dev->pdev->dev, "remove read_list CB\n");
+       list_for_each_entry_safe(pos, next,
+                       &dev->read_list.mei_cb.cb_list, cb_list) {
+               struct mei_cl *cl_temp;
+               cl_temp = (struct mei_cl *)pos->file_private;
+
+               if (mei_cl_cmp_id(cl, cl_temp))
+                       return pos;
+       }
+       return NULL;
+}
+
+/**
+ * mei_open - the open function
+ *
+ * @inode: pointer to inode structure
+ * @file: pointer to file structure
+ *
+ * returns 0 on success, <0 on error
+ */
+static int mei_open(struct inode *inode, struct file *file)
+{
+       struct mei_cl *cl;
+       struct mei_device *dev;
+       unsigned long cl_id;
+       int err;
+
+       err = -ENODEV;
+       if (!mei_device)
+               goto out;
+
+       dev = pci_get_drvdata(mei_device);
+       if (!dev)
+               goto out;
+
+       mutex_lock(&dev->device_lock);
+       err = -ENOMEM;
+       cl = mei_cl_allocate(dev);
+       if (!cl)
+               goto out_unlock;
+
+       err = -ENODEV;
+       if (dev->mei_state != MEI_ENABLED) {
+               dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED  mei_state= %d\n",
+                   dev->mei_state);
+               goto out_unlock;
+       }
+       err = -EMFILE;
+       if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT)
+               goto out_unlock;
+
+       cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
+       if (cl_id >= MEI_CLIENTS_MAX)
+               goto out_unlock;
+
+       cl->host_client_id  = cl_id;
+
+       dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id);
+
+       dev->open_handle_count++;
+
+       list_add_tail(&cl->link, &dev->file_list);
+
+       set_bit(cl->host_client_id, dev->host_clients_map);
+       cl->state = MEI_FILE_INITIALIZING;
+       cl->sm_state = 0;
+
+       file->private_data = cl;
+       mutex_unlock(&dev->device_lock);
+
+       return nonseekable_open(inode, file);
+
+out_unlock:
+       mutex_unlock(&dev->device_lock);
+       kfree(cl);
+out:
+       return err;
+}
+
+/**
+ * mei_release - the release function
+ *
+ * @inode: pointer to inode structure
+ * @file: pointer to file structure
+ *
+ * returns 0 on success, <0 on error
+ */
+static int mei_release(struct inode *inode, struct file *file)
+{
+       struct mei_cl *cl = file->private_data;
+       struct mei_cl_cb *cb;
+       struct mei_device *dev;
+       int rets = 0;
+
+       if (WARN_ON(!cl || !cl->dev))
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       mutex_lock(&dev->device_lock);
+       if (cl != &dev->iamthif_cl) {
+               if (cl->state == MEI_FILE_CONNECTED) {
+                       cl->state = MEI_FILE_DISCONNECTING;
+                       dev_dbg(&dev->pdev->dev,
+                               "disconnecting client host client = %d, "
+                           "ME client = %d\n",
+                           cl->host_client_id,
+                           cl->me_client_id);
+                       rets = mei_disconnect_host_client(dev, cl);
+               }
+               mei_cl_flush_queues(cl);
+               dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
+                   cl->host_client_id,
+                   cl->me_client_id);
+
+               if (dev->open_handle_count > 0) {
+                       clear_bit(cl->host_client_id, dev->host_clients_map);
+                       dev->open_handle_count--;
+               }
+               mei_remove_client_from_file_list(dev, cl->host_client_id);
+
+               /* free read cb */
+               cb = NULL;
+               if (cl->read_cb) {
+                       cb = find_read_list_entry(dev, cl);
+                       /* Remove entry from read list */
+                       if (cb)
+                               list_del(&cb->cb_list);
+
+                       cb = cl->read_cb;
+                       cl->read_cb = NULL;
+               }
+
+               file->private_data = NULL;
+
+               if (cb) {
+                       mei_free_cb_private(cb);
+                       cb = NULL;
+               }
+
+               kfree(cl);
+       } else {
+               if (dev->open_handle_count > 0)
+                       dev->open_handle_count--;
+
+               if (dev->iamthif_file_object == file &&
+                   dev->iamthif_state != MEI_IAMTHIF_IDLE) {
+
+                       dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n",
+                           dev->iamthif_state);
+                       dev->iamthif_canceled = true;
+                       if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
+                               dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n");
+                               mei_run_next_iamthif_cmd(dev);
+                       }
+               }
+
+               if (mei_clear_lists(dev, file))
+                       dev->iamthif_state = MEI_IAMTHIF_IDLE;
+
+       }
+       mutex_unlock(&dev->device_lock);
+       return rets;
+}
+
+
+/**
+ * mei_read - the read 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 mei_read(struct file *file, char __user *ubuf,
+                       size_t length, loff_t *offset)
+{
+       struct mei_cl *cl = file->private_data;
+       struct mei_cl_cb *cb_pos = NULL;
+       struct mei_cl_cb *cb = NULL;
+       struct mei_device *dev;
+       int i;
+       int rets;
+       int err;
+
+
+       if (WARN_ON(!cl || !cl->dev))
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       mutex_lock(&dev->device_lock);
+       if (dev->mei_state != MEI_ENABLED) {
+               rets = -ENODEV;
+               goto out;
+       }
+
+       if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
+               /* Do not allow to read watchdog client */
+               i = mei_find_me_client_index(dev, mei_wd_guid);
+               if (i >= 0) {
+                       struct mei_me_client *me_client = &dev->me_clients[i];
+
+                       if (cl->me_client_id == me_client->client_id) {
+                               rets = -EBADF;
+                               goto out;
+                       }
+               }
+       } else {
+               cl->sm_state &= ~MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
+       }
+
+       if (cl == &dev->iamthif_cl) {
+               rets = amthi_read(dev, file, ubuf, length, offset);
+               goto out;
+       }
+
+       if (cl->read_cb && cl->read_cb->information > *offset) {
+               cb = cl->read_cb;
+               goto copy_buffer;
+       } else if (cl->read_cb && cl->read_cb->information > 0 &&
+                  cl->read_cb->information <= *offset) {
+               cb = cl->read_cb;
+               rets = 0;
+               goto free;
+       } else if ((!cl->read_cb || !cl->read_cb->information) &&
+                   *offset > 0) {
+               /*Offset needs to be cleaned for contiguous reads*/
+               *offset = 0;
+               rets = 0;
+               goto out;
+       }
+
+       err = mei_start_read(dev, cl);
+       if (err && err != -EBUSY) {
+               dev_dbg(&dev->pdev->dev,
+                       "mei start read failure with status = %d\n", err);
+               rets = err;
+               goto out;
+       }
+
+       if (MEI_READ_COMPLETE != cl->reading_state &&
+                       !waitqueue_active(&cl->rx_wait)) {
+               if (file->f_flags & O_NONBLOCK) {
+                       rets = -EAGAIN;
+                       goto out;
+               }
+
+               mutex_unlock(&dev->device_lock);
+
+               if (wait_event_interruptible(cl->rx_wait,
+                       (MEI_READ_COMPLETE == cl->reading_state ||
+                        MEI_FILE_INITIALIZING == cl->state ||
+                        MEI_FILE_DISCONNECTED == cl->state ||
+                        MEI_FILE_DISCONNECTING == cl->state))) {
+                       if (signal_pending(current))
+                               return -EINTR;
+                       return -ERESTARTSYS;
+               }
+
+               mutex_lock(&dev->device_lock);
+               if (MEI_FILE_INITIALIZING == cl->state ||
+                   MEI_FILE_DISCONNECTED == cl->state ||
+                   MEI_FILE_DISCONNECTING == cl->state) {
+                       rets = -EBUSY;
+                       goto out;
+               }
+       }
+
+       cb = cl->read_cb;
+
+       if (!cb) {
+               rets = -ENODEV;
+               goto out;
+       }
+       if (cl->reading_state != MEI_READ_COMPLETE) {
+               rets = 0;
+               goto out;
+       }
+       /* now copy the data to user space */
+copy_buffer:
+       dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n",
+           cb->response_buffer.size);
+       dev_dbg(&dev->pdev->dev, "cb->information - %lu\n",
+           cb->information);
+       if (length == 0 || ubuf == NULL || *offset > cb->information) {
+               rets = -EMSGSIZE;
+               goto free;
+       }
+
+       /* length is being truncated to PAGE_SIZE, however, */
+       /* information size may be longer */
+       length = min_t(size_t, length, (cb->information - *offset));
+
+       if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+               rets = -EFAULT;
+               goto free;
+       }
+
+       rets = length;
+       *offset += length;
+       if ((unsigned long)*offset < cb->information)
+               goto out;
+
+free:
+       cb_pos = find_read_list_entry(dev, cl);
+       /* Remove entry from read list */
+       if (cb_pos)
+               list_del(&cb_pos->cb_list);
+       mei_free_cb_private(cb);
+       cl->reading_state = MEI_IDLE;
+       cl->read_cb = NULL;
+       cl->read_pending = 0;
+out:
+       dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
+       mutex_unlock(&dev->device_lock);
+       return rets;
+}
+
+/**
+ * mei_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 mei_write(struct file *file, const char __user *ubuf,
+                        size_t length, loff_t *offset)
+{
+       struct mei_cl *cl = file->private_data;
+       struct mei_cl_cb *write_cb = NULL;
+       struct mei_msg_hdr mei_hdr;
+       struct mei_device *dev;
+       unsigned long timeout = 0;
+       int rets;
+       int i;
+
+       if (WARN_ON(!cl || !cl->dev))
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       mutex_lock(&dev->device_lock);
+
+       if (dev->mei_state != MEI_ENABLED) {
+               mutex_unlock(&dev->device_lock);
+               return -ENODEV;
+       }
+
+       if (cl == &dev->iamthif_cl) {
+               write_cb = find_amthi_read_list_entry(dev, file);
+
+               if (write_cb) {
+                       timeout = write_cb->read_time +
+                                       msecs_to_jiffies(IAMTHIF_READ_TIMER);
+
+                       if (time_after(jiffies, timeout) ||
+                                cl->reading_state == MEI_READ_COMPLETE) {
+                                       *offset = 0;
+                                       list_del(&write_cb->cb_list);
+                                       mei_free_cb_private(write_cb);
+                                       write_cb = NULL;
+                       }
+               }
+       }
+
+       /* free entry used in read */
+       if (cl->reading_state == MEI_READ_COMPLETE) {
+               *offset = 0;
+               write_cb = find_read_list_entry(dev, cl);
+               if (write_cb) {
+                       list_del(&write_cb->cb_list);
+                       mei_free_cb_private(write_cb);
+                       write_cb = NULL;
+                       cl->reading_state = MEI_IDLE;
+                       cl->read_cb = NULL;
+                       cl->read_pending = 0;
+               }
+       } else if (cl->reading_state == MEI_IDLE && !cl->read_pending)
+               *offset = 0;
+
+
+       write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+       if (!write_cb) {
+               mutex_unlock(&dev->device_lock);
+               return -ENOMEM;
+       }
+
+       write_cb->file_object = file;
+       write_cb->file_private = cl;
+       write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
+       rets = -ENOMEM;
+       if (!write_cb->request_buffer.data)
+               goto unlock_dev;
+
+       dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length);
+
+       rets = -EFAULT;
+       if (copy_from_user(write_cb->request_buffer.data, ubuf, length))
+               goto unlock_dev;
+
+       cl->sm_state = 0;
+       if (length == 4 &&
+           ((memcmp(mei_wd_state_independence_msg[0],
+                                write_cb->request_buffer.data, 4) == 0) ||
+            (memcmp(mei_wd_state_independence_msg[1],
+                                write_cb->request_buffer.data, 4) == 0) ||
+            (memcmp(mei_wd_state_independence_msg[2],
+                                write_cb->request_buffer.data, 4) == 0)))
+               cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
+
+       INIT_LIST_HEAD(&write_cb->cb_list);
+       if (cl == &dev->iamthif_cl) {
+               write_cb->response_buffer.data =
+                   kmalloc(dev->iamthif_mtu, GFP_KERNEL);
+               if (!write_cb->response_buffer.data) {
+                       rets = -ENOMEM;
+                       goto unlock_dev;
+               }
+               if (dev->mei_state != MEI_ENABLED) {
+                       rets = -ENODEV;
+                       goto unlock_dev;
+               }
+               for (i = 0; i < dev->me_clients_num; i++) {
+                       if (dev->me_clients[i].client_id ==
+                               dev->iamthif_cl.me_client_id)
+                               break;
+               }
+
+               if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
+                       rets = -ENODEV;
+                       goto unlock_dev;
+               }
+               if (i == dev->me_clients_num ||
+                   (dev->me_clients[i].client_id !=
+                     dev->iamthif_cl.me_client_id)) {
+                       rets = -ENODEV;
+                       goto unlock_dev;
+               } else if (length > dev->me_clients[i].props.max_msg_length ||
+                          length <= 0) {
+                       rets = -EMSGSIZE;
+                       goto unlock_dev;
+               }
+
+               write_cb->response_buffer.size = dev->iamthif_mtu;
+               write_cb->major_file_operations = MEI_IOCTL;
+               write_cb->information = 0;
+               write_cb->request_buffer.size = length;
+               if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
+                       rets = -ENODEV;
+                       goto unlock_dev;
+               }
+
+               if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) ||
+                               dev->iamthif_state != MEI_IAMTHIF_IDLE) {
+                       dev_dbg(&dev->pdev->dev, "amthi_state = %d\n",
+                                       (int) dev->iamthif_state);
+                       dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n");
+                       list_add_tail(&write_cb->cb_list,
+                                       &dev->amthi_cmd_list.mei_cb.cb_list);
+                       rets = length;
+               } else {
+                       dev_dbg(&dev->pdev->dev, "call amthi write\n");
+                       rets = amthi_write(dev, write_cb);
+
+                       if (rets) {
+                               dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n",
+                                   rets);
+                               goto unlock_dev;
+                       }
+                       rets = length;
+               }
+               mutex_unlock(&dev->device_lock);
+               return rets;
+       }
+
+       write_cb->major_file_operations = MEI_WRITE;
+       /* make sure information is zero before we start */
+
+       write_cb->information = 0;
+       write_cb->request_buffer.size = length;
+
+       dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
+           cl->host_client_id, cl->me_client_id);
+       if (cl->state != MEI_FILE_CONNECTED) {
+               rets = -ENODEV;
+               dev_dbg(&dev->pdev->dev, "host client = %d,  is not connected to ME client = %d",
+                   cl->host_client_id,
+                   cl->me_client_id);
+               goto unlock_dev;
+       }
+       for (i = 0; i < dev->me_clients_num; i++) {
+               if (dev->me_clients[i].client_id ==
+                   cl->me_client_id)
+                       break;
+       }
+       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
+               rets = -ENODEV;
+               goto unlock_dev;
+       }
+       if (i == dev->me_clients_num) {
+               rets = -ENODEV;
+               goto unlock_dev;
+       }
+       if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
+               rets = -EINVAL;
+               goto unlock_dev;
+       }
+       write_cb->file_private = cl;
+
+       rets = mei_flow_ctrl_creds(dev, cl);
+       if (rets < 0)
+               goto unlock_dev;
+
+       if (rets && dev->mei_host_buffer_is_empty) {
+               rets = 0;
+               dev->mei_host_buffer_is_empty = false;
+               if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
+                       sizeof(u32)) - sizeof(struct mei_msg_hdr))) {
+
+                       mei_hdr.length =
+                               (((dev->host_hw_state & H_CBD) >> 24) *
+                               sizeof(u32)) -
+                               sizeof(struct mei_msg_hdr);
+                       mei_hdr.msg_complete = 0;
+               } else {
+                       mei_hdr.length = length;
+                       mei_hdr.msg_complete = 1;
+               }
+               mei_hdr.host_addr = cl->host_client_id;
+               mei_hdr.me_addr = cl->me_client_id;
+               mei_hdr.reserved = 0;
+               dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n",
+                   *((u32 *) &mei_hdr));
+               if (mei_write_message(dev, &mei_hdr,
+                       (unsigned char *) (write_cb->request_buffer.data),
+                       mei_hdr.length)) {
+                       rets = -ENODEV;
+                       goto unlock_dev;
+               }
+               cl->writing_state = MEI_WRITING;
+               write_cb->information = mei_hdr.length;
+               if (mei_hdr.msg_complete) {
+                       if (mei_flow_ctrl_reduce(dev, cl)) {
+                               rets = -ENODEV;
+                               goto unlock_dev;
+                       }
+                       list_add_tail(&write_cb->cb_list,
+                                     &dev->write_waiting_list.mei_cb.cb_list);
+               } else {
+                       list_add_tail(&write_cb->cb_list,
+                                     &dev->write_list.mei_cb.cb_list);
+               }
+
+       } else {
+
+               write_cb->information = 0;
+               cl->writing_state = MEI_WRITING;
+               list_add_tail(&write_cb->cb_list,
+                             &dev->write_list.mei_cb.cb_list);
+       }
+       mutex_unlock(&dev->device_lock);
+       return length;
+
+unlock_dev:
+       mutex_unlock(&dev->device_lock);
+       mei_free_cb_private(write_cb);
+       return rets;
+}
+
+
+/**
+ * mei_ioctl - the IOCTL function
+ *
+ * @file: pointer to file structure
+ * @cmd: ioctl command
+ * @data: pointer to mei message structure
+ *
+ * returns 0 on success , <0 on error
+ */
+static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
+{
+       struct mei_device *dev;
+       struct mei_cl *cl = file->private_data;
+       struct mei_connect_client_data *connect_data = NULL;
+       int rets;
+
+       if (cmd != IOCTL_MEI_CONNECT_CLIENT)
+               return -EINVAL;
+
+       if (WARN_ON(!cl || !cl->dev))
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
+
+       mutex_lock(&dev->device_lock);
+       if (dev->mei_state != MEI_ENABLED) {
+               rets = -ENODEV;
+               goto out;
+       }
+
+       dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
+
+       connect_data = kzalloc(sizeof(struct mei_connect_client_data),
+                                                       GFP_KERNEL);
+       if (!connect_data) {
+               rets = -ENOMEM;
+               goto out;
+       }
+       dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
+       if (copy_from_user(connect_data, (char __user *)data,
+                               sizeof(struct mei_connect_client_data))) {
+               dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
+               rets = -EFAULT;
+               goto out;
+       }
+       rets = mei_ioctl_connect_client(file, connect_data);
+
+       /* if all is ok, copying the data back to user. */
+       if (rets)
+               goto out;
+
+       dev_dbg(&dev->pdev->dev, "copy connect data to user\n");
+       if (copy_to_user((char __user *)data, connect_data,
+                               sizeof(struct mei_connect_client_data))) {
+               dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
+               rets = -EFAULT;
+               goto out;
+       }
+
+out:
+       kfree(connect_data);
+       mutex_unlock(&dev->device_lock);
+       return rets;
+}
+
+/**
+ * mei_compat_ioctl - the compat IOCTL function
+ *
+ * @file: pointer to file structure
+ * @cmd: ioctl command
+ * @data: pointer to mei message structure
+ *
+ * returns 0 on success , <0 on error
+ */
+#ifdef CONFIG_COMPAT
+static long mei_compat_ioctl(struct file *file,
+                       unsigned int cmd, unsigned long data)
+{
+       return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data));
+}
+#endif
+
+
+/**
+ * mei_poll - the poll function
+ *
+ * @file: pointer to file structure
+ * @wait: pointer to poll_table structure
+ *
+ * returns poll mask
+ */
+static unsigned int mei_poll(struct file *file, poll_table *wait)
+{
+       struct mei_cl *cl = file->private_data;
+       struct mei_device *dev;
+       unsigned int mask = 0;
+
+       if (WARN_ON(!cl || !cl->dev))
+               return mask;
+
+       dev = cl->dev;
+
+       mutex_lock(&dev->device_lock);
+
+       if (dev->mei_state != MEI_ENABLED)
+               goto out;
+
+
+       if (cl == &dev->iamthif_cl) {
+               mutex_unlock(&dev->device_lock);
+               poll_wait(file, &dev->iamthif_cl.wait, wait);
+               mutex_lock(&dev->device_lock);
+               if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
+                       dev->iamthif_file_object == file) {
+                       mask |= (POLLIN | POLLRDNORM);
+                       dev_dbg(&dev->pdev->dev, "run next amthi cb\n");
+                       mei_run_next_iamthif_cmd(dev);
+               }
+               goto out;
+       }
+
+       mutex_unlock(&dev->device_lock);
+       poll_wait(file, &cl->tx_wait, wait);
+       mutex_lock(&dev->device_lock);
+       if (MEI_WRITE_COMPLETE == cl->writing_state)
+               mask |= (POLLIN | POLLRDNORM);
+
+out:
+       mutex_unlock(&dev->device_lock);
+       return mask;
+}
+
+/*
+ * file operations structure will be used for mei char device.
+ */
+static const struct file_operations mei_fops = {
+       .owner = THIS_MODULE,
+       .read = mei_read,
+       .unlocked_ioctl = mei_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = mei_compat_ioctl,
+#endif
+       .open = mei_open,
+       .release = mei_release,
+       .write = mei_write,
+       .poll = mei_poll,
+       .llseek = no_llseek
+};
+
+
+/*
+ * Misc Device Struct
+ */
+static struct miscdevice  mei_misc_device = {
+               .name = "mei",
+               .fops = &mei_fops,
+               .minor = MISC_DYNAMIC_MINOR,
+};
+
+/**
+ * mei_probe - Device Initialization Routine
+ *
+ * @pdev: PCI device structure
+ * @ent: entry in kcs_pci_tbl
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int __devinit mei_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       struct mei_device *dev;
+       int err;
+
+       mutex_lock(&mei_mutex);
+       if (mei_device) {
+               err = -EEXIST;
+               goto end;
+       }
+       /* enable pci dev */
+       err = pci_enable_device(pdev);
+       if (err) {
+               printk(KERN_ERR "mei: Failed to enable pci device.\n");
+               goto end;
+       }
+       /* set PCI host mastering  */
+       pci_set_master(pdev);
+       /* pci request regions for mei driver */
+       err = pci_request_regions(pdev, mei_driver_name);
+       if (err) {
+               printk(KERN_ERR "mei: Failed to get pci regions.\n");
+               goto disable_device;
+       }
+       /* allocates and initializes the mei dev structure */
+       dev = mei_device_init(pdev);
+       if (!dev) {
+               err = -ENOMEM;
+               goto release_regions;
+       }
+       /* mapping  IO device memory */
+       dev->mem_addr = pci_iomap(pdev, 0, 0);
+       if (!dev->mem_addr) {
+               printk(KERN_ERR "mei: mapping I/O device memory failure.\n");
+               err = -ENOMEM;
+               goto free_device;
+       }
+       pci_enable_msi(pdev);
+
+        /* request and enable interrupt */
+       if (pci_dev_msi_enabled(pdev))
+               err = request_threaded_irq(pdev->irq,
+                       NULL,
+                       mei_interrupt_thread_handler,
+                       0, mei_driver_name, dev);
+       else
+               err = request_threaded_irq(pdev->irq,
+                       mei_interrupt_quick_handler,
+                       mei_interrupt_thread_handler,
+                       IRQF_SHARED, mei_driver_name, dev);
+
+       if (err) {
+               printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n",
+                      pdev->irq);
+               goto unmap_memory;
+       }
+       INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
+       if (mei_hw_init(dev)) {
+               printk(KERN_ERR "mei: Init hw failure.\n");
+               err = -ENODEV;
+               goto release_irq;
+       }
+
+       err = misc_register(&mei_misc_device);
+       if (err)
+               goto release_irq;
+
+       mei_device = pdev;
+       pci_set_drvdata(pdev, dev);
+
+
+       schedule_delayed_work(&dev->timer_work, HZ);
+
+       mutex_unlock(&mei_mutex);
+
+       pr_debug("initialization successful.\n");
+
+       return 0;
+
+release_irq:
+       /* disable interrupts */
+       dev->host_hw_state = mei_hcsr_read(dev);
+       mei_disable_interrupts(dev);
+       flush_scheduled_work();
+       free_irq(pdev->irq, dev);
+       pci_disable_msi(pdev);
+unmap_memory:
+       pci_iounmap(pdev, dev->mem_addr);
+free_device:
+       kfree(dev);
+release_regions:
+       pci_release_regions(pdev);
+disable_device:
+       pci_disable_device(pdev);
+end:
+       mutex_unlock(&mei_mutex);
+       printk(KERN_ERR "mei: Driver initialization failed.\n");
+       return err;
+}
+
+/**
+ * mei_remove - Device Removal Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+static void __devexit mei_remove(struct pci_dev *pdev)
+{
+       struct mei_device *dev;
+
+       if (mei_device != pdev)
+               return;
+
+       dev = pci_get_drvdata(pdev);
+       if (!dev)
+               return;
+
+       mutex_lock(&dev->device_lock);
+
+       mei_wd_stop(dev, false);
+
+       mei_device = NULL;
+
+       if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
+               dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
+               mei_disconnect_host_client(dev, &dev->iamthif_cl);
+       }
+       if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
+               dev->wd_cl.state = MEI_FILE_DISCONNECTING;
+               mei_disconnect_host_client(dev, &dev->wd_cl);
+       }
+
+       /* Unregistering watchdog device */
+       mei_watchdog_unregister(dev);
+
+       /* remove entry if already in list */
+       dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
+       mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id);
+       mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id);
+
+       dev->iamthif_current_cb = NULL;
+       dev->me_clients_num = 0;
+
+       mutex_unlock(&dev->device_lock);
+
+       flush_scheduled_work();
+
+       /* disable interrupts */
+       mei_disable_interrupts(dev);
+
+       free_irq(pdev->irq, dev);
+       pci_disable_msi(pdev);
+       pci_set_drvdata(pdev, NULL);
+
+       if (dev->mem_addr)
+               pci_iounmap(pdev, dev->mem_addr);
+
+       kfree(dev);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+#ifdef CONFIG_PM
+static int mei_pci_suspend(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct mei_device *dev = pci_get_drvdata(pdev);
+       int err;
+
+       if (!dev)
+               return -ENODEV;
+       mutex_lock(&dev->device_lock);
+       /* Stop watchdog if exists */
+       err = mei_wd_stop(dev, true);
+       /* Set new mei state */
+       if (dev->mei_state == MEI_ENABLED ||
+           dev->mei_state == MEI_RECOVERING_FROM_RESET) {
+               dev->mei_state = MEI_POWER_DOWN;
+               mei_reset(dev, 0);
+       }
+       mutex_unlock(&dev->device_lock);
+
+       free_irq(pdev->irq, dev);
+       pci_disable_msi(pdev);
+
+       return err;
+}
+
+static int mei_pci_resume(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct mei_device *dev;
+       int err;
+
+       dev = pci_get_drvdata(pdev);
+       if (!dev)
+               return -ENODEV;
+
+       pci_enable_msi(pdev);
+
+       /* request and enable interrupt */
+       if (pci_dev_msi_enabled(pdev))
+               err = request_threaded_irq(pdev->irq,
+                       NULL,
+                       mei_interrupt_thread_handler,
+                       0, mei_driver_name, dev);
+       else
+               err = request_threaded_irq(pdev->irq,
+                       mei_interrupt_quick_handler,
+                       mei_interrupt_thread_handler,
+                       IRQF_SHARED, mei_driver_name, dev);
+
+       if (err) {
+               printk(KERN_ERR "mei: Request_irq failure. irq = %d\n",
+                      pdev->irq);
+               return err;
+       }
+
+       mutex_lock(&dev->device_lock);
+       dev->mei_state = MEI_POWER_UP;
+       mei_reset(dev, 1);
+       mutex_unlock(&dev->device_lock);
+
+       /* Start timer if stopped in suspend */
+       schedule_delayed_work(&dev->timer_work, HZ);
+
+       return err;
+}
+static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
+#define MEI_PM_OPS     (&mei_pm_ops)
+#else
+#define MEI_PM_OPS     NULL
+#endif /* CONFIG_PM */
+/*
+ *  PCI driver structure
+ */
+static struct pci_driver mei_driver = {
+       .name = mei_driver_name,
+       .id_table = mei_pci_tbl,
+       .probe = mei_probe,
+       .remove = __devexit_p(mei_remove),
+       .shutdown = __devexit_p(mei_remove),
+       .driver.pm = MEI_PM_OPS,
+};
+
+/**
+ * mei_init_module - Driver Registration Routine
+ *
+ * mei_init_module is the first routine called when the driver is
+ * loaded. All it does is to register with the PCI subsystem.
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int __init mei_init_module(void)
+{
+       int ret;
+
+       pr_debug("loading.\n");
+       /* init pci module */
+       ret = pci_register_driver(&mei_driver);
+       if (ret < 0)
+               printk(KERN_ERR "mei: Error registering driver.\n");
+
+       return ret;
+}
+
+module_init(mei_init_module);
+
+/**
+ * mei_exit_module - Driver Exit Cleanup Routine
+ *
+ * mei_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit mei_exit_module(void)
+{
+       misc_deregister(&mei_misc_device);
+       pci_unregister_driver(&mei_driver);
+
+       pr_debug("unloaded successfully.\n");
+}
+
+module_exit(mei_exit_module);
+
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/mei-amt-version.c b/drivers/misc/mei/mei-amt-version.c
new file mode 100644 (file)
index 0000000..ac2a507
--- /dev/null
@@ -0,0 +1,481 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *     Intel Corporation.
+ *     linux-mei@linux.intel.com
+ *     http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * 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 MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * 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 DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <bits/wordsize.h>
+#include "mei.h"
+
+/*****************************************************************************
+ * Intel Management Engine Interface
+ *****************************************************************************/
+
+#define mei_msg(_me, fmt, ARGS...) do {         \
+       if (_me->verbose)                       \
+               fprintf(stderr, fmt, ##ARGS);   \
+} while (0)
+
+#define mei_err(_me, fmt, ARGS...) do {         \
+       fprintf(stderr, "Error: " fmt, ##ARGS); \
+} while (0)
+
+struct mei {
+       uuid_le guid;
+       bool initialized;
+       bool verbose;
+       unsigned int buf_size;
+       unsigned char prot_ver;
+       int fd;
+};
+
+static void mei_deinit(struct mei *cl)
+{
+       if (cl->fd != -1)
+               close(cl->fd);
+       cl->fd = -1;
+       cl->buf_size = 0;
+       cl->prot_ver = 0;
+       cl->initialized = false;
+}
+
+static bool mei_init(struct mei *me, const uuid_le *guid,
+               unsigned char req_protocol_version, bool verbose)
+{
+       int result;
+       struct mei_client *cl;
+       struct mei_connect_client_data data;
+
+       mei_deinit(me);
+
+       me->verbose = verbose;
+
+       me->fd = open("/dev/mei", O_RDWR);
+       if (me->fd == -1) {
+               mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
+               goto err;
+       }
+       memcpy(&me->guid, guid, sizeof(*guid));
+       memset(&data, 0, sizeof(data));
+       me->initialized = true;
+
+       memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
+       result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
+       if (result) {
+               mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
+               goto err;
+       }
+       cl = &data.out_client_properties;
+       mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
+       mei_msg(me, "protocol_version %d\n", cl->protocol_version);
+
+       if ((req_protocol_version > 0) &&
+            (cl->protocol_version != req_protocol_version)) {
+               mei_err(me, "Intel MEI protocol version not supported\n");
+               goto err;
+       }
+
+       me->buf_size = cl->max_msg_length;
+       me->prot_ver = cl->protocol_version;
+
+       return true;
+err:
+       mei_deinit(me);
+       return false;
+}
+
+static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
+                       ssize_t len, unsigned long timeout)
+{
+       ssize_t rc;
+
+       mei_msg(me, "call read length = %zd\n", len);
+
+       rc = read(me->fd, buffer, len);
+       if (rc < 0) {
+               mei_err(me, "read failed with status %zd %s\n",
+                               rc, strerror(errno));
+               mei_deinit(me);
+       } else {
+               mei_msg(me, "read succeeded with result %zd\n", rc);
+       }
+       return rc;
+}
+
+static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
+                       ssize_t len, unsigned long timeout)
+{
+       struct timeval tv;
+       ssize_t written;
+       ssize_t rc;
+       fd_set set;
+
+       tv.tv_sec = timeout / 1000;
+       tv.tv_usec = (timeout % 1000) * 1000000;
+
+       mei_msg(me, "call write length = %zd\n", len);
+
+       written = write(me->fd, buffer, len);
+       if (written < 0) {
+               rc = -errno;
+               mei_err(me, "write failed with status %zd %s\n",
+                       written, strerror(errno));
+               goto out;
+       }
+
+       FD_ZERO(&set);
+       FD_SET(me->fd, &set);
+       rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
+       if (rc > 0 && FD_ISSET(me->fd, &set)) {
+               mei_msg(me, "write success\n");
+       } else if (rc == 0) {
+               mei_err(me, "write failed on timeout with status\n");
+               goto out;
+       } else { /* rc < 0 */
+               mei_err(me, "write failed on select with status %zd\n", rc);
+               goto out;
+       }
+
+       rc = written;
+out:
+       if (rc < 0)
+               mei_deinit(me);
+
+       return rc;
+}
+
+/***************************************************************************
+ * Intel Advanced Management Technolgy ME Client
+ ***************************************************************************/
+
+#define AMT_MAJOR_VERSION 1
+#define AMT_MINOR_VERSION 1
+
+#define AMT_STATUS_SUCCESS                0x0
+#define AMT_STATUS_INTERNAL_ERROR         0x1
+#define AMT_STATUS_NOT_READY              0x2
+#define AMT_STATUS_INVALID_AMT_MODE       0x3
+#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
+
+#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE  0x4000
+#define AMT_STATUS_SDK_RESOURCES      0x1004
+
+
+#define AMT_BIOS_VERSION_LEN   65
+#define AMT_VERSIONS_NUMBER    50
+#define AMT_UNICODE_STRING_LEN 20
+
+struct amt_unicode_string {
+       uint16_t length;
+       char string[AMT_UNICODE_STRING_LEN];
+} __attribute__((packed));
+
+struct amt_version_type {
+       struct amt_unicode_string description;
+       struct amt_unicode_string version;
+} __attribute__((packed));
+
+struct amt_version {
+       uint8_t major;
+       uint8_t minor;
+} __attribute__((packed));
+
+struct amt_code_versions {
+       uint8_t bios[AMT_BIOS_VERSION_LEN];
+       uint32_t count;
+       struct amt_version_type versions[AMT_VERSIONS_NUMBER];
+} __attribute__((packed));
+
+/***************************************************************************
+ * Intel Advanced Management Technolgy Host Interface
+ ***************************************************************************/
+
+struct amt_host_if_msg_header {
+       struct amt_version version;
+       uint16_t _reserved;
+       uint32_t command;
+       uint32_t length;
+} __attribute__((packed));
+
+struct amt_host_if_resp_header {
+       struct amt_host_if_msg_header header;
+       uint32_t status;
+       unsigned char data[0];
+} __attribute__((packed));
+
+const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,  \
+                               0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
+
+#define AMT_HOST_IF_CODE_VERSIONS_REQUEST  0x0400001A
+#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
+
+const struct amt_host_if_msg_header CODE_VERSION_REQ = {
+       .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
+       ._reserved = 0,
+       .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
+       .length = 0
+};
+
+
+struct amt_host_if {
+       struct mei mei_cl;
+       unsigned long send_timeout;
+       bool initialized;
+};
+
+
+static bool amt_host_if_init(struct amt_host_if *acmd,
+                     unsigned long send_timeout, bool verbose)
+{
+       acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
+       acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
+       return acmd->initialized;
+}
+
+static void amt_host_if_deinit(struct amt_host_if *acmd)
+{
+       mei_deinit(&acmd->mei_cl);
+       acmd->initialized = false;
+}
+
+static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
+{
+       uint32_t status = AMT_STATUS_SUCCESS;
+       struct amt_code_versions *code_ver;
+       size_t code_ver_len;
+       uint32_t ver_type_cnt;
+       uint32_t len;
+       uint32_t i;
+
+       code_ver = (struct amt_code_versions *)resp->data;
+       /* length - sizeof(status) */
+       code_ver_len = resp->header.length - sizeof(uint32_t);
+       ver_type_cnt = code_ver_len -
+                       sizeof(code_ver->bios) -
+                       sizeof(code_ver->count);
+       if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
+               status = AMT_STATUS_INTERNAL_ERROR;
+               goto out;
+       }
+
+       for (i = 0; i < code_ver->count; i++) {
+               len = code_ver->versions[i].description.length;
+
+               if (len > AMT_UNICODE_STRING_LEN) {
+                       status = AMT_STATUS_INTERNAL_ERROR;
+                       goto out;
+               }
+
+               len = code_ver->versions[i].version.length;
+               if (code_ver->versions[i].version.string[len] != '\0' ||
+                   len != strlen(code_ver->versions[i].version.string)) {
+                       status = AMT_STATUS_INTERNAL_ERROR;
+                       goto out;
+               }
+       }
+out:
+       return status;
+}
+
+static uint32_t amt_verify_response_header(uint32_t command,
+                               const struct amt_host_if_msg_header *resp_hdr,
+                               uint32_t response_size)
+{
+       if (response_size < sizeof(struct amt_host_if_resp_header)) {
+               return AMT_STATUS_INTERNAL_ERROR;
+       } else if (response_size != (resp_hdr->length +
+                               sizeof(struct amt_host_if_msg_header))) {
+               return AMT_STATUS_INTERNAL_ERROR;
+       } else if (resp_hdr->command != command) {
+               return AMT_STATUS_INTERNAL_ERROR;
+       } else if (resp_hdr->_reserved != 0) {
+               return AMT_STATUS_INTERNAL_ERROR;
+       } else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
+                  resp_hdr->version.minor < AMT_MINOR_VERSION) {
+               return AMT_STATUS_INTERNAL_ERROR;
+       }
+       return AMT_STATUS_SUCCESS;
+}
+
+static uint32_t amt_host_if_call(struct amt_host_if *acmd,
+                       const unsigned char *command, ssize_t command_sz,
+                       uint8_t **read_buf, uint32_t rcmd,
+                       unsigned int expected_sz)
+{
+       uint32_t in_buf_sz;
+       uint32_t out_buf_sz;
+       ssize_t written;
+       uint32_t status;
+       struct amt_host_if_resp_header *msg_hdr;
+
+       in_buf_sz = acmd->mei_cl.buf_size;
+       *read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
+       if (*read_buf == NULL)
+               return AMT_STATUS_SDK_RESOURCES;
+       memset(*read_buf, 0, in_buf_sz);
+       msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
+
+       written = mei_send_msg(&acmd->mei_cl,
+                               command, command_sz, acmd->send_timeout);
+       if (written != command_sz)
+               return AMT_STATUS_INTERNAL_ERROR;
+
+       out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
+       if (out_buf_sz <= 0)
+               return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
+
+       status = msg_hdr->status;
+       if (status != AMT_STATUS_SUCCESS)
+               return status;
+
+       status = amt_verify_response_header(rcmd,
+                               &msg_hdr->header, out_buf_sz);
+       if (status != AMT_STATUS_SUCCESS)
+               return status;
+
+       if (expected_sz && expected_sz != out_buf_sz)
+               return AMT_STATUS_INTERNAL_ERROR;
+
+       return AMT_STATUS_SUCCESS;
+}
+
+
+static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
+                              struct amt_code_versions *versions)
+{
+       struct amt_host_if_resp_header *response = NULL;
+       uint32_t status;
+
+       status = amt_host_if_call(cmd,
+                       (const unsigned char *)&CODE_VERSION_REQ,
+                       sizeof(CODE_VERSION_REQ),
+                       (uint8_t **)&response,
+                       AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
+
+       if (status != AMT_STATUS_SUCCESS)
+               goto out;
+
+       status = amt_verify_code_versions(response);
+       if (status != AMT_STATUS_SUCCESS)
+               goto out;
+
+       memcpy(versions, response->data, sizeof(struct amt_code_versions));
+out:
+       if (response != NULL)
+               free(response);
+
+       return status;
+}
+
+/************************** end of amt_host_if_command ***********************/
+int main(int argc, char **argv)
+{
+       struct amt_code_versions ver;
+       struct amt_host_if acmd;
+       unsigned int i;
+       uint32_t status;
+       int ret;
+       bool verbose;
+
+       verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
+
+       if (!amt_host_if_init(&acmd, 5000, verbose)) {
+               ret = 1;
+               goto out;
+       }
+
+       status = amt_get_code_versions(&acmd, &ver);
+
+       amt_host_if_deinit(&acmd);
+
+       switch (status) {
+       case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
+               printf("Intel AMT: DISABLED\n");
+               ret = 0;
+               break;
+       case AMT_STATUS_SUCCESS:
+               printf("Intel AMT: ENABLED\n");
+               for (i = 0; i < ver.count; i++) {
+                       printf("%s:\t%s\n", ver.versions[i].description.string,
+                               ver.versions[i].version.string);
+               }
+               ret = 0;
+               break;
+       default:
+               printf("An error has occurred\n");
+               ret = 1;
+               break;
+       }
+
+out:
+       return ret;
+}
diff --git a/drivers/misc/mei/mei.h b/drivers/misc/mei/mei.h
new file mode 100644 (file)
index 0000000..bc0d8b6
--- /dev/null
@@ -0,0 +1,110 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *     Intel Corporation.
+ *     linux-mei@linux.intel.com
+ *     http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * 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 MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * 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 DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef _LINUX_MEI_H
+#define _LINUX_MEI_H
+
+#include <linux/uuid.h>
+
+/*
+ * This IOCTL is used to associate the current file descriptor with a
+ * FW Client (given by UUID). This opens a communication channel
+ * between a host client and a FW client. From this point every read and write
+ * will communicate with the associated FW client.
+ * Only in close() (file_operation release()) the communication between
+ * the clients is disconnected
+ *
+ * The IOCTL argument is a struct with a union that contains
+ * the input parameter and the output parameter for this IOCTL.
+ *
+ * The input parameter is UUID of the FW Client.
+ * The output parameter is the properties of the FW client
+ * (FW protocol version and max message size).
+ *
+ */
+#define IOCTL_MEI_CONNECT_CLIENT \
+       _IOWR('H' , 0x01, struct mei_connect_client_data)
+
+/*
+ * Intel MEI client information struct
+ */
+struct mei_client {
+       __u32 max_msg_length;
+       __u8 protocol_version;
+       __u8 reserved[3];
+};
+
+/*
+ * IOCTL Connect Client Data structure
+ */
+struct mei_connect_client_data {
+       union {
+               uuid_le in_client_uuid;
+               struct mei_client out_client_properties;
+       };
+};
+
+#endif /* _LINUX_MEI_H  */
diff --git a/drivers/misc/mei/mei.txt b/drivers/misc/mei/mei.txt
new file mode 100644 (file)
index 0000000..2785697
--- /dev/null
@@ -0,0 +1,215 @@
+Intel(R) Management Engine Interface (Intel(R) MEI)
+=======================
+
+Introduction
+=======================
+
+The Intel Management Engine (Intel ME) is an isolated and protected computing
+resource (Co-processor) residing inside certain Intel chipsets. The Intel ME
+provides support for computer/IT management features. The feature set
+depends on the Intel chipset SKU.
+
+The Intel Management Engine Interface (Intel MEI, previously known as HECI)
+is the interface between the Host and Intel ME. This interface is exposed
+to the host as a PCI device. The Intel MEI Driver is in charge of the
+communication channel between a host application and the Intel ME feature.
+
+Each Intel ME feature (Intel ME Client) is addressed by a GUID/UUID and
+each client has its own protocol. The protocol is message-based with a
+header and payload up to 512 bytes.
+
+Prominent usage of the Intel ME Interface is to communicate with Intel(R)
+Active Management Technology (Intel AMT)implemented in firmware running on
+the Intel ME.
+
+Intel AMT provides the ability to manage a host remotely out-of-band (OOB)
+even when the operating system running on the host processor has crashed or
+is in a sleep state.
+
+Some examples of Intel AMT usage are:
+   - Monitoring hardware state and platform components
+   - Remote power off/on (useful for green computing or overnight IT
+     maintenance)
+   - OS updates
+   - Storage of useful platform information such as software assets
+   - Built-in hardware KVM
+   - Selective network isolation of Ethernet and IP protocol flows based
+     on policies set by a remote management console
+   - IDE device redirection from remote management console
+
+Intel AMT (OOB) communication is based on SOAP (deprecated
+starting with Release 6.0) over HTTP/S or WS-Management protocol over
+HTTP/S that are received from a remote management console application.
+
+For more information about Intel AMT:
+http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
+
+Intel MEI Driver
+=======================
+
+The driver exposes a misc device called /dev/mei.
+
+An application maintains communication with an Intel ME feature while
+/dev/mei is open. The binding to a specific features is performed by calling
+MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID.
+The number of instances of an Intel ME feature that can be opened
+at the same time depends on the Intel ME feature, but most of the
+features allow only a single instance.
+
+The Intel AMT Host Interface (Intel AMTHI) feature supports multiple
+simultaneous user applications. Therefore, the Intel MEI driver handles
+this internally by maintaining request queues for the applications.
+
+The driver is oblivious to data that is passed between firmware feature
+and host application.
+
+Because some of the Intel ME features can change the system
+configuration, the driver by default allows only a privileged
+user to access it.
+
+A code snippet for an application communicating with
+Intel AMTHI client:
+       struct mei_connect_client_data data;
+       fd = open(MEI_DEVICE);
+
+       data.d.in_client_uuid = AMTHI_UUID;
+
+       ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &data);
+
+       printf("Ver=%d, MaxLen=%ld\n",
+                       data.d.in_client_uuid.protocol_version,
+                       data.d.in_client_uuid.max_msg_length);
+
+       [...]
+
+       write(fd, amthi_req_data, amthi_req_data_len);
+
+       [...]
+
+       read(fd, &amthi_res_data, amthi_res_data_len);
+
+       [...]
+       close(fd);
+
+IOCTL:
+======
+The Intel MEI Driver supports the following IOCTL command:
+       IOCTL_MEI_CONNECT_CLIENT        Connect to firmware Feature (client).
+
+       usage:
+               struct mei_connect_client_data clientData;
+               ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &clientData);
+
+       inputs:
+               mei_connect_client_data struct contain the following
+               input field:
+
+               in_client_uuid -        UUID of the FW Feature that needs
+                                       to connect to.
+       outputs:
+               out_client_properties - Client Properties: MTU and Protocol Version.
+
+       error returns:
+               EINVAL  Wrong IOCTL Number
+               ENODEV  Device or Connection is not initialized or ready.
+                       (e.g. Wrong UUID)
+               ENOMEM  Unable to allocate memory to client internal data.
+               EFAULT  Fatal Error (e.g. Unable to access user input data)
+               EBUSY   Connection Already Open
+
+       Notes:
+        max_msg_length (MTU) in client properties describes the maximum
+        data that can be sent or received. (e.g. if MTU=2K, can send
+        requests up to bytes 2k and received responses upto 2k bytes).
+
+Intel ME Applications:
+==============
+
+1) Intel Local Management Service (Intel LMS)
+
+       Applications running locally on the platform communicate with Intel AMT Release
+       2.0 and later releases in the same way that network applications do via SOAP
+       over HTTP (deprecated starting with Release 6.0) or with WS-Management over
+       SOAP over HTTP. This means that some Intel AMT features can be accessed from a
+       local application using the same network interface as a remote application
+       communicating with Intel AMT over the network.
+
+       When a local application sends a message addressed to the local Intel AMT host
+       name, the Intel LMS, which listens for traffic directed to the host name,
+       intercepts the message and routes it to the Intel MEI.
+       For more information:
+       http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
+       Under "About Intel AMT" => "Local Access"
+
+       For downloading Intel LMS:
+       http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/
+
+       The Intel LMS opens a connection using the Intel MEI driver to the Intel LMS
+       firmware feature using a defined UUID and then communicates with the feature
+       using a protocol called Intel AMT Port Forwarding Protocol(Intel APF protocol).
+       The protocol is used to maintain multiple sessions with Intel AMT from a
+       single application.
+
+       See the protocol specification in the Intel AMT Software Development Kit(SDK)
+       http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
+       Under "SDK Resources" => "Intel(R) vPro(TM) Gateway(MPS)"
+       => "Information for Intel(R) vPro(TM) Gateway Developers"
+       => "Description of the Intel AMT Port Forwarding (APF)Protocol"
+
+  2) Intel AMT Remote configuration using a Local Agent
+       A Local Agent enables IT personnel to configure Intel AMT out-of-the-box
+       without requiring installing additional data to enable setup. The remote
+       configuration process may involve an ISV-developed remote configuration
+       agent that runs on the host.
+       For more information:
+       http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
+       Under "Setup and Configuration of Intel AMT" =>
+       "SDK Tools Supporting Setup and Configuration" =>
+       "Using the Local Agent Sample"
+
+       An open source Intel AMT configuration utility, implementing a local agent
+       that accesses the Intel MEI driver, can be found here:
+       http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/
+
+
+Intel AMT OS Health Watchdog:
+=============================
+The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog.
+Whenever the OS hangs or crashes, Intel AMT will send an event
+to any subscriber to this event. This mechanism means that
+IT knows when a platform crashes even when there is a hard failure on the host.
+
+The Intel AMT Watchdog is composed of two parts:
+       1) Firmware feature - receives the heartbeats
+          and sends an event when the heartbeats stop.
+       2) Intel MEI driver - connects to the watchdog feature, configures the
+          watchdog and sends the heartbeats.
+
+The Intel MEI driver uses the kernel watchdog to configure the Intel AMT
+Watchdog and to send heartbeats to it. The default timeout of the
+watchdog is 120 seconds.
+
+If the Intel AMT Watchdog feature does not exist (i.e. the connection failed),
+the Intel MEI driver will disable the sending of heartbeats.
+
+Supported Chipsets:
+==================
+7 Series Chipset Family
+6 Series Chipset Family
+5 Series Chipset Family
+4 Series Chipset Family
+Mobile 4 Series Chipset Family
+ICH9
+82946GZ/GL
+82G35 Express
+82Q963/Q965
+82P965/G965
+Mobile PM965/GM965
+Mobile GME965/GLE960
+82Q35 Express
+82G33/G31/P35/P31 Express
+82Q33 Express
+82X38/X48 Express
+
+---
+linux-mei@linux.intel.com
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
new file mode 100644 (file)
index 0000000..10b1b4e
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _MEI_DEV_H_
+#define _MEI_DEV_H_
+
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include "mei.h"
+#include "hw.h"
+
+/*
+ * watch dog definition
+ */
+#define MEI_WATCHDOG_DATA_SIZE         16
+#define MEI_START_WD_DATA_SIZE         20
+#define MEI_WD_PARAMS_SIZE             4
+#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT       (1 << 0)
+
+#define MEI_RD_MSG_BUF_SIZE           (128 * sizeof(u32))
+
+/*
+ * MEI PCI Device object
+ */
+extern struct pci_dev *mei_device;
+
+
+/*
+ * AMTHI Client UUID
+ */
+extern const uuid_le mei_amthi_guid;
+
+/*
+ * Watchdog Client UUID
+ */
+extern const uuid_le mei_wd_guid;
+
+/*
+ * Watchdog independence state message
+ */
+extern const u8 mei_wd_state_independence_msg[3][4];
+
+/*
+ * Number of File descriptors/handles
+ * that can be opened to the driver.
+ *
+ * Limit to 253: 255 Total Clients
+ * minus internal client for AMTHI
+ * minus internal client for Watchdog
+ */
+#define  MEI_MAX_OPEN_HANDLE_COUNT     253
+
+/*
+ * Number of Maximum MEI Clients
+ */
+#define MEI_CLIENTS_MAX 255
+
+/* File state */
+enum file_state {
+       MEI_FILE_INITIALIZING = 0,
+       MEI_FILE_CONNECTING,
+       MEI_FILE_CONNECTED,
+       MEI_FILE_DISCONNECTING,
+       MEI_FILE_DISCONNECTED
+};
+
+/* MEI device states */
+enum mei_states {
+       MEI_INITIALIZING = 0,
+       MEI_INIT_CLIENTS,
+       MEI_ENABLED,
+       MEI_RESETING,
+       MEI_DISABLED,
+       MEI_RECOVERING_FROM_RESET,
+       MEI_POWER_DOWN,
+       MEI_POWER_UP
+};
+
+/* init clients states*/
+enum mei_init_clients_states {
+       MEI_START_MESSAGE = 0,
+       MEI_ENUM_CLIENTS_MESSAGE,
+       MEI_CLIENT_PROPERTIES_MESSAGE
+};
+
+enum iamthif_states {
+       MEI_IAMTHIF_IDLE,
+       MEI_IAMTHIF_WRITING,
+       MEI_IAMTHIF_FLOW_CONTROL,
+       MEI_IAMTHIF_READING,
+       MEI_IAMTHIF_READ_COMPLETE
+};
+
+enum mei_file_transaction_states {
+       MEI_IDLE,
+       MEI_WRITING,
+       MEI_WRITE_COMPLETE,
+       MEI_FLOW_CONTROL,
+       MEI_READING,
+       MEI_READ_COMPLETE
+};
+
+/* MEI CB */
+enum mei_cb_major_types {
+       MEI_READ = 0,
+       MEI_WRITE,
+       MEI_IOCTL,
+       MEI_OPEN,
+       MEI_CLOSE
+};
+
+/*
+ * Intel MEI message data struct
+ */
+struct mei_message_data {
+       u32 size;
+       unsigned char *data;
+} __packed;
+
+
+struct mei_cl_cb {
+       struct list_head cb_list;
+       enum mei_cb_major_types major_file_operations;
+       void *file_private;
+       struct mei_message_data request_buffer;
+       struct mei_message_data response_buffer;
+       unsigned long information;
+       unsigned long read_time;
+       struct file *file_object;
+};
+
+/* MEI client instance carried as file->pirvate_data*/
+struct mei_cl {
+       struct list_head link;
+       struct mei_device *dev;
+       enum file_state state;
+       wait_queue_head_t tx_wait;
+       wait_queue_head_t rx_wait;
+       wait_queue_head_t wait;
+       int read_pending;
+       int status;
+       /* ID of client connected */
+       u8 host_client_id;
+       u8 me_client_id;
+       u8 mei_flow_ctrl_creds;
+       u8 timer_count;
+       enum mei_file_transaction_states reading_state;
+       enum mei_file_transaction_states writing_state;
+       int sm_state;
+       struct mei_cl_cb *read_cb;
+};
+
+struct mei_io_list {
+       struct mei_cl_cb mei_cb;
+};
+
+/* MEI private device struct */
+struct mei_device {
+       struct pci_dev *pdev;   /* pointer to pci device struct */
+       /*
+        * lists of queues
+        */
+        /* array of pointers to aio lists */
+       struct mei_io_list read_list;           /* driver read queue */
+       struct mei_io_list write_list;          /* driver write queue */
+       struct mei_io_list write_waiting_list;  /* write waiting queue */
+       struct mei_io_list ctrl_wr_list;        /* managed write IOCTL list */
+       struct mei_io_list ctrl_rd_list;        /* managed read IOCTL list */
+       struct mei_io_list amthi_cmd_list;      /* amthi list for cmd waiting */
+
+       /* driver managed amthi list for reading completed amthi cmd data */
+       struct mei_io_list amthi_read_complete_list;
+       /*
+        * list of files
+        */
+       struct list_head file_list;
+       long open_handle_count;
+       /*
+        * memory of device
+        */
+       unsigned int mem_base;
+       unsigned int mem_length;
+       void __iomem *mem_addr;
+       /*
+        * lock for the device
+        */
+       struct mutex device_lock; /* device lock */
+       struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
+       bool recvd_msg;
+       /*
+        * 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;
+
+       /*
+        * mei device  states
+        */
+       enum mei_states mei_state;
+       enum mei_init_clients_states init_clients_state;
+       u16 init_clients_timer;
+       bool stop;
+       bool need_reset;
+
+       u32 extra_write_index;
+       unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];  /* 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;
+
+       struct mei_me_client *me_clients; /* Note: memory has to be allocated */
+       DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
+       DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
+       u8 me_clients_num;
+       u8 me_client_presentation_num;
+       u8 me_client_index;
+       bool mei_host_buffer_is_empty;
+
+       struct mei_cl wd_cl;
+       bool wd_pending;
+       bool wd_stopped;
+       bool wd_bypass; /* if false, don't refresh watchdog ME client */
+       u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
+       u16 wd_due_counter;
+       unsigned char wd_data[MEI_START_WD_DATA_SIZE];
+
+
+
+       struct file *iamthif_file_object;
+       struct mei_cl iamthif_cl;
+       struct mei_cl_cb *iamthif_current_cb;
+       int iamthif_mtu;
+       unsigned long iamthif_timer;
+       u32 iamthif_stall_timer;
+       unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */
+       u32 iamthif_msg_buf_size;
+       u32 iamthif_msg_buf_index;
+       enum iamthif_states iamthif_state;
+       bool iamthif_flow_control_pending;
+       bool iamthif_ioctl;
+       bool iamthif_canceled;
+
+       bool wd_interface_reg;
+};
+
+
+/*
+ * mei init function prototypes
+ */
+struct mei_device *mei_device_init(struct pci_dev *pdev);
+void mei_reset(struct mei_device *dev, int interrupts);
+int mei_hw_init(struct mei_device *dev);
+int mei_task_initialize_clients(void *data);
+int mei_initialize_clients(struct mei_device *dev);
+int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl);
+void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id);
+void mei_host_init_iamthif(struct mei_device *dev);
+void mei_allocate_me_clients_storage(struct mei_device *dev);
+
+
+u8 mei_find_me_client_update_filext(struct mei_device *dev,
+                               struct mei_cl *priv,
+                               const uuid_le *cguid, u8 client_id);
+
+/*
+ * MEI IO List Functions
+ */
+void mei_io_list_init(struct mei_io_list *list);
+void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl);
+
+/*
+ * MEI ME Client Functions
+ */
+
+struct mei_cl *mei_cl_allocate(struct mei_device *dev);
+void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
+int mei_cl_flush_queues(struct mei_cl *cl);
+/**
+ * mei_cl_cmp_id - tells if file private data have same id
+ *
+ * @fe1: private data of 1. file object
+ * @fe2: private data of 2. file object
+ *
+ * returns true  - if ids are the same and not NULL
+ */
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+                               const struct mei_cl *cl2)
+{
+       return cl1 && cl2 &&
+               (cl1->host_client_id == cl2->host_client_id) &&
+               (cl1->me_client_id == cl2->me_client_id);
+}
+
+
+
+/*
+ * MEI Host Client Functions
+ */
+void mei_host_start_message(struct mei_device *dev);
+void mei_host_enum_clients_message(struct mei_device *dev);
+int mei_host_client_properties(struct mei_device *dev);
+
+/*
+ *  MEI interrupt functions prototype
+ */
+irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id);
+irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
+void mei_timer(struct work_struct *work);
+
+/*
+ *  MEI input output function prototype
+ */
+int mei_ioctl_connect_client(struct file *file,
+                       struct mei_connect_client_data *data);
+
+int mei_start_read(struct mei_device *dev, struct mei_cl *cl);
+
+int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb);
+
+int amthi_read(struct mei_device *dev, struct file *file,
+             char __user *ubuf, size_t length, loff_t *offset);
+
+struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev,
+                                               struct file *file);
+
+void mei_run_next_iamthif_cmd(struct mei_device *dev);
+
+void mei_free_cb_private(struct mei_cl_cb *priv_cb);
+
+int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
+
+/*
+ * Register Access Function
+ */
+
+/**
+ * mei_reg_read - Reads 32bit data from the mei device
+ *
+ * @dev: the device structure
+ * @offset: offset from which to read the data
+ *
+ * returns register value (u32)
+ */
+static inline u32 mei_reg_read(struct mei_device *dev, unsigned long offset)
+{
+       return ioread32(dev->mem_addr + offset);
+}
+
+/**
+ * mei_reg_write - Writes 32bit data to the mei device
+ *
+ * @dev: the device structure
+ * @offset: offset from which to write the data
+ * @value: register value to write (u32)
+ */
+static inline void mei_reg_write(struct mei_device *dev,
+                               unsigned long offset, u32 value)
+{
+       iowrite32(value, dev->mem_addr + offset);
+}
+
+/**
+ * mei_hcsr_read - Reads 32bit data from the host CSR
+ *
+ * @dev: the device structure
+ *
+ * returns the byte read.
+ */
+static inline u32 mei_hcsr_read(struct mei_device *dev)
+{
+       return mei_reg_read(dev, H_CSR);
+}
+
+/**
+ * mei_mecsr_read - Reads 32bit data from the ME CSR
+ *
+ * @dev: the device structure
+ *
+ * returns ME_CSR_HA register value (u32)
+ */
+static inline u32 mei_mecsr_read(struct mei_device *dev)
+{
+       return mei_reg_read(dev, ME_CSR_HA);
+}
+
+/**
+ * get_me_cb_rw - Reads 32bit data from the mei ME_CB_RW register
+ *
+ * @dev: the device structure
+ *
+ * returns ME_CB_RW register value (u32)
+ */
+static inline u32 mei_mecbrw_read(struct mei_device *dev)
+{
+       return mei_reg_read(dev, ME_CB_RW);
+}
+
+
+/*
+ * mei interface function prototypes
+ */
+void mei_hcsr_set(struct mei_device *dev);
+void mei_csr_clear_his(struct mei_device *dev);
+
+void mei_enable_interrupts(struct mei_device *dev);
+void mei_disable_interrupts(struct mei_device *dev);
+
+#endif
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
new file mode 100644 (file)
index 0000000..1e62851
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/watchdog.h>
+
+#include "mei_dev.h"
+#include "hw.h"
+#include "interface.h"
+#include "mei.h"
+
+static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
+static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
+
+const u8 mei_wd_state_independence_msg[3][4] = {
+       {0x05, 0x02, 0x51, 0x10},
+       {0x05, 0x02, 0x52, 0x10},
+       {0x07, 0x02, 0x01, 0x10}
+};
+
+/*
+ * AMT Watchdog Device
+ */
+#define INTEL_AMT_WATCHDOG_ID "INTCAMT"
+
+/* UUIDs for AMT F/W clients */
+const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
+                                               0x9D, 0xA9, 0x15, 0x14, 0xCB,
+                                               0x32, 0xAB);
+
+static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
+{
+       dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
+       memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
+       memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16));
+}
+
+/**
+ * host_init_wd - mei initialization wd.
+ *
+ * @dev: the device structure
+ * returns -ENENT if wd client cannot be found
+ *         -EIO if write has failed
+ */
+int mei_wd_host_init(struct mei_device *dev)
+{
+       mei_cl_init(&dev->wd_cl, dev);
+
+       /* look for WD client and connect to it */
+       dev->wd_cl.state = MEI_FILE_DISCONNECTED;
+       dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT;
+
+       /* find ME WD client */
+       mei_find_me_client_update_filext(dev, &dev->wd_cl,
+                               &mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
+
+       dev_dbg(&dev->pdev->dev, "wd: check client\n");
+       if (MEI_FILE_CONNECTING != dev->wd_cl.state) {
+               dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
+               return -ENOENT;
+       }
+
+       if (mei_connect(dev, &dev->wd_cl)) {
+               dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
+               dev->wd_cl.state = MEI_FILE_DISCONNECTED;
+               dev->wd_cl.host_client_id = 0;
+               return -EIO;
+       }
+       dev->wd_cl.timer_count = CONNECT_TIMEOUT;
+
+       return 0;
+}
+
+/**
+ * mei_wd_send - sends watch dog message to fw.
+ *
+ * @dev: the device structure
+ *
+ * returns 0 if success,
+ *     -EIO when message send fails
+ *     -EINVAL when invalid message is to be sent
+ */
+int mei_wd_send(struct mei_device *dev)
+{
+       struct mei_msg_hdr *mei_hdr;
+
+       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
+       mei_hdr->host_addr = dev->wd_cl.host_client_id;
+       mei_hdr->me_addr = dev->wd_cl.me_client_id;
+       mei_hdr->msg_complete = 1;
+       mei_hdr->reserved = 0;
+
+       if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
+               mei_hdr->length = MEI_START_WD_DATA_SIZE;
+       else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
+               mei_hdr->length = MEI_WD_PARAMS_SIZE;
+       else
+               return -EINVAL;
+
+       return mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length);
+}
+
+/**
+ * mei_wd_stop - sends watchdog stop message to fw.
+ *
+ * @dev: the device structure
+ * @preserve: indicate if to keep the timeout value
+ *
+ * returns 0 if success,
+ *     -EIO when message send fails
+ *     -EINVAL when invalid message is to be sent
+ */
+int mei_wd_stop(struct mei_device *dev, bool preserve)
+{
+       int ret;
+       u16 wd_timeout = dev->wd_timeout;
+
+       cancel_delayed_work(&dev->timer_work);
+       if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
+               return 0;
+
+       dev->wd_timeout = 0;
+       dev->wd_due_counter = 0;
+       memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
+       dev->stop = true;
+
+       ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
+       if (ret < 0)
+               goto out;
+
+       if (ret && dev->mei_host_buffer_is_empty) {
+               ret = 0;
+               dev->mei_host_buffer_is_empty = false;
+
+               if (!mei_wd_send(dev)) {
+                       ret = mei_flow_ctrl_reduce(dev, &dev->wd_cl);
+                       if (ret)
+                               goto out;
+               } else {
+                       dev_err(&dev->pdev->dev, "wd: send stop failed\n");
+               }
+
+               dev->wd_pending = false;
+       } else {
+               dev->wd_pending = true;
+       }
+       dev->wd_stopped = false;
+       mutex_unlock(&dev->device_lock);
+
+       ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
+                                       dev->wd_stopped, 10 * HZ);
+       mutex_lock(&dev->device_lock);
+       if (dev->wd_stopped) {
+               dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
+               ret = 0;
+       } else {
+               if (!ret)
+                       ret = -ETIMEDOUT;
+               dev_warn(&dev->pdev->dev,
+                       "wd: stop failed to complete ret=%d.\n", ret);
+       }
+
+       if (preserve)
+               dev->wd_timeout = wd_timeout;
+
+out:
+       return ret;
+}
+
+/*
+ * mei_wd_ops_start - wd start command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_start(struct watchdog_device *wd_dev)
+{
+       int err = -ENODEV;
+       struct mei_device *dev;
+
+       dev = pci_get_drvdata(mei_device);
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->device_lock);
+
+       if (dev->mei_state != MEI_ENABLED) {
+               dev_dbg(&dev->pdev->dev,
+                       "wd: mei_state != MEI_ENABLED  mei_state = %d\n",
+                       dev->mei_state);
+               goto end_unlock;
+       }
+
+       if (dev->wd_cl.state != MEI_FILE_CONNECTED)     {
+               dev_dbg(&dev->pdev->dev,
+                       "MEI Driver is not connected to Watchdog Client\n");
+               goto end_unlock;
+       }
+
+       mei_wd_set_start_timeout(dev, dev->wd_timeout);
+
+       err = 0;
+end_unlock:
+       mutex_unlock(&dev->device_lock);
+       return err;
+}
+
+/*
+ * mei_wd_ops_stop -  wd stop command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
+{
+       struct mei_device *dev;
+       dev = pci_get_drvdata(mei_device);
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->device_lock);
+       mei_wd_stop(dev, false);
+       mutex_unlock(&dev->device_lock);
+
+       return 0;
+}
+
+/*
+ * mei_wd_ops_ping - wd ping command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
+{
+       int ret = 0;
+       struct mei_device *dev;
+       dev = pci_get_drvdata(mei_device);
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->device_lock);
+
+       if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
+               dev_err(&dev->pdev->dev, "wd: not connected.\n");
+               ret = -ENODEV;
+               goto end;
+       }
+
+       /* Check if we can send the ping to HW*/
+       if (dev->mei_host_buffer_is_empty &&
+               mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
+
+               dev->mei_host_buffer_is_empty = false;
+               dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
+
+               if (mei_wd_send(dev)) {
+                       dev_err(&dev->pdev->dev, "wd: send failed.\n");
+                       ret = -EIO;
+                       goto end;
+               }
+
+               if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) {
+                       dev_err(&dev->pdev->dev,
+                               "wd: mei_flow_ctrl_reduce() failed.\n");
+                       ret = -EIO;
+                       goto end;
+               }
+
+       } else {
+               dev->wd_pending = true;
+       }
+
+end:
+       mutex_unlock(&dev->device_lock);
+       return ret;
+}
+
+/*
+ * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ * @timeout - timeout value to set
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
+{
+       struct mei_device *dev;
+       dev = pci_get_drvdata(mei_device);
+
+       if (!dev)
+               return -ENODEV;
+
+       /* Check Timeout value */
+       if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT)
+               return -EINVAL;
+
+       mutex_lock(&dev->device_lock);
+
+       dev->wd_timeout = timeout;
+       wd_dev->timeout = timeout;
+       mei_wd_set_start_timeout(dev, dev->wd_timeout);
+
+       mutex_unlock(&dev->device_lock);
+
+       return 0;
+}
+
+/*
+ * Watchdog Device structs
+ */
+static const struct watchdog_ops wd_ops = {
+               .owner = THIS_MODULE,
+               .start = mei_wd_ops_start,
+               .stop = mei_wd_ops_stop,
+               .ping = mei_wd_ops_ping,
+               .set_timeout = mei_wd_ops_set_timeout,
+};
+static const struct watchdog_info wd_info = {
+               .identity = INTEL_AMT_WATCHDOG_ID,
+               .options = WDIOF_KEEPALIVEPING,
+};
+
+static struct watchdog_device amt_wd_dev = {
+               .info = &wd_info,
+               .ops = &wd_ops,
+               .timeout = AMT_WD_DEFAULT_TIMEOUT,
+               .min_timeout = AMT_WD_MIN_TIMEOUT,
+               .max_timeout = AMT_WD_MAX_TIMEOUT,
+};
+
+
+void  mei_watchdog_register(struct mei_device *dev)
+{
+       dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout);
+
+       dev->wd_due_counter = !!dev->wd_timeout;
+
+       if (watchdog_register_device(&amt_wd_dev)) {
+               dev_err(&dev->pdev->dev,
+                       "wd: unable to register watchdog device.\n");
+               dev->wd_interface_reg = false;
+       } else {
+               dev_dbg(&dev->pdev->dev,
+                       "wd: successfully register watchdog interface.\n");
+               dev->wd_interface_reg = true;
+       }
+}
+
+void mei_watchdog_unregister(struct mei_device *dev)
+{
+       if (dev->wd_interface_reg)
+               watchdog_unregister_device(&amt_wd_dev);
+       dev->wd_interface_reg = false;
+}
+
index 60221efc417bb8576027ccc0ff3c9c67a79d1e73..32b02e443ed348d5ecdbfb2d7282004ede5100a7 100644 (file)
@@ -112,8 +112,6 @@ source "drivers/staging/cptm1217/Kconfig"
 
 source "drivers/staging/ste_rmi4/Kconfig"
 
-source "drivers/staging/mei/Kconfig"
-
 source "drivers/staging/nvec/Kconfig"
 
 source "drivers/staging/media/Kconfig"
index 03819581fefac34265d8eadb475ba51e69b3f016..e603c07569604a9bdb1cd820b9a8ac069e895400 100644 (file)
@@ -50,7 +50,6 @@ obj-$(CONFIG_FT1000)          += ft1000/
 obj-$(CONFIG_SPEAKUP)          += speakup/
 obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)      += cptm1217/
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)   += ste_rmi4/
-obj-$(CONFIG_INTEL_MEI)                += mei/
 obj-$(CONFIG_MFD_NVEC)         += nvec/
 obj-$(CONFIG_DRM_OMAP)         += omapdrm/
 obj-$(CONFIG_ANDROID)          += android/
diff --git a/drivers/staging/mei/Kconfig b/drivers/staging/mei/Kconfig
deleted file mode 100644 (file)
index 47d78a7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-config INTEL_MEI
-       tristate "Intel Management Engine Interface (Intel MEI)"
-       depends on X86 && PCI && EXPERIMENTAL && WATCHDOG_CORE
-       help
-         The Intel Management Engine (Intel ME) provides Manageability,
-         Security and Media services for system containing Intel chipsets.
-         if selected /dev/mei misc device will be created.
-
-         Supported Chipsets are:
-         7 Series Chipset Family
-         6 Series Chipset Family
-         5 Series Chipset Family
-         4 Series Chipset Family
-         Mobile 4 Series Chipset Family
-         ICH9
-         82946GZ/GL
-         82G35 Express
-         82Q963/Q965
-         82P965/G965
-         Mobile PM965/GM965
-         Mobile GME965/GLE960
-         82Q35 Express
-         82G33/G31/P35/P31 Express
-         82Q33 Express
-         82X38/X48 Express
-
-         For more information see
-         <http://software.intel.com/en-us/manageability/>
diff --git a/drivers/staging/mei/Makefile b/drivers/staging/mei/Makefile
deleted file mode 100644 (file)
index 57168db..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile - Intel Management Engine Interface (Intel MEI) Linux driver
-# Copyright (c) 2010-2011, Intel Corporation.
-#
-obj-$(CONFIG_INTEL_MEI) += mei.o
-mei-objs := init.o
-mei-objs += interrupt.o
-mei-objs += interface.o
-mei-objs += iorw.o
-mei-objs += main.o
-mei-objs += wd.o
diff --git a/drivers/staging/mei/TODO b/drivers/staging/mei/TODO
deleted file mode 100644 (file)
index fc26601..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-TODO:
-       - Cleanup and split the timer function
-Upon Unstaging:
-       - move mei.h to include/linux/mei.h
-       - Documentation/ioctl/ioctl-number.txt
-       - move mei.txt under Documentation/mei/
-       - move mei-amt-version.c under Documentation/mei
-       - add hostprogs-y for mei-amt-version.c
-       - drop mei_version.h
-       - Updated MAINTAINERS
diff --git a/drivers/staging/mei/hw.h b/drivers/staging/mei/hw.h
deleted file mode 100644 (file)
index 24c4c96..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-#ifndef _MEI_HW_TYPES_H_
-#define _MEI_HW_TYPES_H_
-
-#include <linux/uuid.h>
-
-/*
- * Timeouts
- */
-#define MEI_INTEROP_TIMEOUT    (HZ * 7)
-#define MEI_CONNECT_TIMEOUT            3       /* at least 2 seconds */
-
-#define CONNECT_TIMEOUT        15      /* HPS definition */
-#define INIT_CLIENTS_TIMEOUT   15      /* HPS definition */
-
-#define IAMTHIF_STALL_TIMER            12      /* seconds */
-#define IAMTHIF_READ_TIMER             10000   /* ms */
-
-/*
- * Internal Clients Number
- */
-#define MEI_WD_HOST_CLIENT_ID          1
-#define MEI_IAMTHIF_HOST_CLIENT_ID     2
-
-/*
- * MEI device IDs
- */
-#define    MEI_DEV_ID_82946GZ  0x2974  /* 82946GZ/GL */
-#define    MEI_DEV_ID_82G35    0x2984  /* 82G35 Express */
-#define    MEI_DEV_ID_82Q965   0x2994  /* 82Q963/Q965 */
-#define    MEI_DEV_ID_82G965   0x29A4  /* 82P965/G965 */
-
-#define    MEI_DEV_ID_82GM965  0x2A04  /* Mobile PM965/GM965 */
-#define    MEI_DEV_ID_82GME965 0x2A14  /* Mobile GME965/GLE960 */
-
-#define    MEI_DEV_ID_ICH9_82Q35 0x29B4  /* 82Q35 Express */
-#define    MEI_DEV_ID_ICH9_82G33 0x29C4  /* 82G33/G31/P35/P31 Express */
-#define    MEI_DEV_ID_ICH9_82Q33 0x29D4  /* 82Q33 Express */
-#define    MEI_DEV_ID_ICH9_82X38 0x29E4  /* 82X38/X48 Express */
-#define    MEI_DEV_ID_ICH9_3200  0x29F4  /* 3200/3210 Server */
-
-#define    MEI_DEV_ID_ICH9_6   0x28B4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_7   0x28C4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_8   0x28D4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_9    0x28E4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_10  0x28F4  /* Bearlake */
-
-#define    MEI_DEV_ID_ICH9M_1  0x2A44  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_2  0x2A54  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_3  0x2A64  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_4  0x2A74  /* Cantiga */
-
-#define    MEI_DEV_ID_ICH10_1  0x2E04  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_2  0x2E14  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_3  0x2E24  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_4  0x2E34  /* Eaglelake */
-
-#define    MEI_DEV_ID_IBXPK_1  0x3B64  /* Calpella */
-#define    MEI_DEV_ID_IBXPK_2  0x3B65  /* Calpella */
-
-#define    MEI_DEV_ID_CPT_1    0x1C3A    /* Cougerpoint */
-#define    MEI_DEV_ID_PBG_1    0x1D3A    /* PBG */
-
-#define    MEI_DEV_ID_PPT_1    0x1E3A    /* Pantherpoint PPT */
-#define    MEI_DEV_ID_PPT_2    0x1CBA    /* Pantherpoint PPT */
-#define    MEI_DEV_ID_PPT_3    0x1DBA    /* Pantherpoint PPT */
-
-
-/*
- * MEI HW Section
- */
-
-/* MEI 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
-
-/*
- * MEI Version
- */
-#define HBM_MINOR_VERSION                   0
-#define HBM_MAJOR_VERSION                   1
-#define HBM_TIMEOUT                         1  /* 1 second */
-
-/* Host bus message command opcode */
-#define MEI_HBM_CMD_OP_MSK                  0x7f
-/* Host bus message command RESPONSE */
-#define MEI_HBM_CMD_RES_MSK                 0x80
-
-/*
- * MEI Bus Message Command IDs
- */
-#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_PROPERTIES_REQ_CMD      0x05
-#define HOST_CLIENT_PROPERTIES_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 MEI_FLOW_CONTROL_CMD                0x08
-
-/*
- * MEI Stop Reason
- * used by hbm_host_stop_request.reason
- */
-enum mei_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
-};
-
-/*
- * Client Connect Status
- * used by hbm_client_connect_response.status
- */
-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
-};
-
-/*
- * Client Disconnect Status
- */
-enum client_disconnect_status_types {
-       CDS_SUCCESS = 0x00
-};
-
-/*
- *  MEI BUS Interface Section
- */
-struct mei_msg_hdr {
-       u32 me_addr:8;
-       u32 host_addr:8;
-       u32 length:9;
-       u32 reserved:6;
-       u32 msg_complete:1;
-} __packed;
-
-
-struct mei_bus_message {
-       u8 hbm_cmd;
-       u8 data[0];
-} __packed;
-
-struct hbm_version {
-       u8 minor_version;
-       u8 major_version;
-} __packed;
-
-struct hbm_host_version_request {
-       u8 hbm_cmd;
-       u8 reserved;
-       struct hbm_version host_version;
-} __packed;
-
-struct hbm_host_version_response {
-       u8 hbm_cmd;
-       u8 host_version_supported;
-       struct hbm_version me_max_version;
-} __packed;
-
-struct hbm_host_stop_request {
-       u8 hbm_cmd;
-       u8 reason;
-       u8 reserved[2];
-} __packed;
-
-struct hbm_host_stop_response {
-       u8 hbm_cmd;
-       u8 reserved[3];
-} __packed;
-
-struct hbm_me_stop_request {
-       u8 hbm_cmd;
-       u8 reason;
-       u8 reserved[2];
-} __packed;
-
-struct hbm_host_enum_request {
-       u8 hbm_cmd;
-       u8 reserved[3];
-} __packed;
-
-struct hbm_host_enum_response {
-       u8 hbm_cmd;
-       u8 reserved[3];
-       u8 valid_addresses[32];
-} __packed;
-
-struct mei_client_properties {
-       uuid_le protocol_name;
-       u8 protocol_version;
-       u8 max_number_of_connections;
-       u8 fixed_address;
-       u8 single_recv_buf;
-       u32 max_msg_length;
-} __packed;
-
-struct hbm_props_request {
-       u8 hbm_cmd;
-       u8 address;
-       u8 reserved[2];
-} __packed;
-
-
-struct hbm_props_response {
-       u8 hbm_cmd;
-       u8 address;
-       u8 status;
-       u8 reserved[1];
-       struct mei_client_properties client_properties;
-} __packed;
-
-struct hbm_client_connect_request {
-       u8 hbm_cmd;
-       u8 me_addr;
-       u8 host_addr;
-       u8 reserved;
-} __packed;
-
-struct hbm_client_connect_response {
-       u8 hbm_cmd;
-       u8 me_addr;
-       u8 host_addr;
-       u8 status;
-} __packed;
-
-struct hbm_client_disconnect_request {
-       u8 hbm_cmd;
-       u8 me_addr;
-       u8 host_addr;
-       u8 reserved[1];
-} __packed;
-
-#define MEI_FC_MESSAGE_RESERVED_LENGTH           5
-
-struct hbm_flow_control {
-       u8 hbm_cmd;
-       u8 me_addr;
-       u8 host_addr;
-       u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH];
-} __packed;
-
-struct mei_me_client {
-       struct mei_client_properties props;
-       u8 client_id;
-       u8 mei_flow_ctrl_creds;
-} __packed;
-
-
-#endif
diff --git a/drivers/staging/mei/init.c b/drivers/staging/mei/init.c
deleted file mode 100644 (file)
index afb0a58..0000000
+++ /dev/null
@@ -1,735 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-
-#include "mei_dev.h"
-#include "hw.h"
-#include "interface.h"
-#include "mei.h"
-
-const uuid_le mei_amthi_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
-                                               0xa8, 0x46, 0xe0, 0xff, 0x65,
-                                               0x81, 0x4c);
-
-/**
- * mei_io_list_init - Sets up a queue list.
- *
- * @list: An instance io list structure
- * @dev: the device structure
- */
-void mei_io_list_init(struct mei_io_list *list)
-{
-       /* initialize our queue list */
-       INIT_LIST_HEAD(&list->mei_cb.cb_list);
-}
-
-/**
- * mei_io_list_flush - removes list entry belonging to cl.
- *
- * @list:  An instance of our list structure
- * @cl: private data of the file object
- */
-void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl)
-{
-       struct mei_cl_cb *pos;
-       struct mei_cl_cb *next;
-
-       list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) {
-               if (pos->file_private) {
-                       struct mei_cl *cl_tmp;
-                       cl_tmp = (struct mei_cl *)pos->file_private;
-                       if (mei_cl_cmp_id(cl, cl_tmp))
-                               list_del(&pos->cb_list);
-               }
-       }
-}
-/**
- * mei_cl_flush_queues - flushes queue lists belonging to cl.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- */
-int mei_cl_flush_queues(struct mei_cl *cl)
-{
-       if (!cl || !cl->dev)
-               return -EINVAL;
-
-       dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
-       mei_io_list_flush(&cl->dev->read_list, cl);
-       mei_io_list_flush(&cl->dev->write_list, cl);
-       mei_io_list_flush(&cl->dev->write_waiting_list, cl);
-       mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
-       mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
-       mei_io_list_flush(&cl->dev->amthi_cmd_list, cl);
-       mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl);
-       return 0;
-}
-
-
-
-/**
- * mei_reset_iamthif_params - initializes mei device iamthif
- *
- * @dev: the device structure
- */
-static void mei_reset_iamthif_params(struct mei_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 = false;
-       dev->iamthif_ioctl = false;
-       dev->iamthif_state = MEI_IAMTHIF_IDLE;
-       dev->iamthif_timer = 0;
-}
-
-/**
- * init_mei_device - allocates and initializes the mei device structure
- *
- * @pdev: The pci device structure
- *
- * returns The mei_device_device pointer on success, NULL on failure.
- */
-struct mei_device *mei_device_init(struct pci_dev *pdev)
-{
-       struct mei_device *dev;
-
-       dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
-       if (!dev)
-               return NULL;
-
-       /* setup our list array */
-       INIT_LIST_HEAD(&dev->file_list);
-       INIT_LIST_HEAD(&dev->wd_cl.link);
-       INIT_LIST_HEAD(&dev->iamthif_cl.link);
-       mutex_init(&dev->device_lock);
-       init_waitqueue_head(&dev->wait_recvd_msg);
-       init_waitqueue_head(&dev->wait_stop_wd);
-       dev->mei_state = MEI_INITIALIZING;
-       dev->iamthif_state = MEI_IAMTHIF_IDLE;
-       dev->wd_interface_reg = false;
-
-
-       mei_io_list_init(&dev->read_list);
-       mei_io_list_init(&dev->write_list);
-       mei_io_list_init(&dev->write_waiting_list);
-       mei_io_list_init(&dev->ctrl_wr_list);
-       mei_io_list_init(&dev->ctrl_rd_list);
-       mei_io_list_init(&dev->amthi_cmd_list);
-       mei_io_list_init(&dev->amthi_read_complete_list);
-       dev->pdev = pdev;
-       return dev;
-}
-
-/**
- * mei_hw_init - initializes host and fw to start work.
- *
- * @dev: the device structure
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_hw_init(struct mei_device *dev)
-{
-       int err = 0;
-       int ret;
-
-       mutex_lock(&dev->device_lock);
-
-       dev->host_hw_state = mei_hcsr_read(dev);
-       dev->me_hw_state = mei_mecsr_read(dev);
-       dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n",
-           dev->host_hw_state, dev->me_hw_state);
-
-       /* acknowledge interrupt and stop interupts */
-       if ((dev->host_hw_state & H_IS) == H_IS)
-               mei_reg_write(dev, H_CSR, dev->host_hw_state);
-
-       dev->recvd_msg = false;
-       dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
-
-       mei_reset(dev, 1);
-
-       dev_dbg(&dev->pdev->dev, "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) {
-               mutex_unlock(&dev->device_lock);
-               err = wait_event_interruptible_timeout(dev->wait_recvd_msg,
-                       dev->recvd_msg, MEI_INTEROP_TIMEOUT);
-               mutex_lock(&dev->device_lock);
-       }
-
-       if (err <= 0 && !dev->recvd_msg) {
-               dev->mei_state = MEI_DISABLED;
-               dev_dbg(&dev->pdev->dev,
-                       "wait_event_interruptible_timeout failed"
-                       "on wait for ME to turn on ME_RDY.\n");
-               ret = -ENODEV;
-               goto out;
-       }
-
-       if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
-             ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
-               dev->mei_state = MEI_DISABLED;
-               dev_dbg(&dev->pdev->dev,
-                       "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))
-                       dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n");
-
-               if (!(dev->me_hw_state & ME_RDY_HRA))
-                       dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
-
-               dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
-               ret = -ENODEV;
-               goto out;
-       }
-
-       if (dev->version.major_version != HBM_MAJOR_VERSION ||
-           dev->version.minor_version != HBM_MINOR_VERSION) {
-               dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
-               ret = -ENODEV;
-               goto out;
-       }
-
-       dev->recvd_msg = false;
-       dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
-           dev->host_hw_state, dev->me_hw_state);
-       dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n");
-       dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
-       dev_dbg(&dev->pdev->dev, "MEI  start success.\n");
-       ret = 0;
-
-out:
-       mutex_unlock(&dev->device_lock);
-       return ret;
-}
-
-/**
- * mei_hw_reset - resets fw via mei csr register.
- *
- * @dev: the device structure
- * @interrupts_enabled: if interrupt should be enabled after reset.
- */
-static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled)
-{
-       dev->host_hw_state |= (H_RST | H_IG);
-
-       if (interrupts_enabled)
-               mei_enable_interrupts(dev);
-       else
-               mei_disable_interrupts(dev);
-}
-
-/**
- * mei_reset - resets host and fw.
- *
- * @dev: the device structure
- * @interrupts_enabled: if interrupt should be enabled after reset.
- */
-void mei_reset(struct mei_device *dev, int interrupts_enabled)
-{
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
-       struct mei_cl_cb *cb_pos = NULL;
-       struct mei_cl_cb *cb_next = NULL;
-       bool unexpected;
-
-       if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
-               dev->need_reset = true;
-               return;
-       }
-
-       unexpected = (dev->mei_state != MEI_INITIALIZING &&
-                       dev->mei_state != MEI_DISABLED &&
-                       dev->mei_state != MEI_POWER_DOWN &&
-                       dev->mei_state != MEI_POWER_UP);
-
-       dev->host_hw_state = mei_hcsr_read(dev);
-
-       dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n",
-           dev->host_hw_state);
-
-       mei_hw_reset(dev, interrupts_enabled);
-
-       dev->host_hw_state &= ~H_RST;
-       dev->host_hw_state |= H_IG;
-
-       mei_hcsr_set(dev);
-
-       dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n",
-           dev->host_hw_state);
-
-       dev->need_reset = false;
-
-       if (dev->mei_state != MEI_INITIALIZING) {
-               if (dev->mei_state != MEI_DISABLED &&
-                   dev->mei_state != MEI_POWER_DOWN)
-                       dev->mei_state = MEI_RESETING;
-
-               list_for_each_entry_safe(cl_pos,
-                               cl_next, &dev->file_list, link) {
-                       cl_pos->state = MEI_FILE_DISCONNECTED;
-                       cl_pos->mei_flow_ctrl_creds = 0;
-                       cl_pos->read_cb = NULL;
-                       cl_pos->timer_count = 0;
-               }
-               /* remove entry if already in list */
-               dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n");
-               mei_remove_client_from_file_list(dev,
-                               dev->wd_cl.host_client_id);
-
-               mei_remove_client_from_file_list(dev,
-                               dev->iamthif_cl.host_client_id);
-
-               mei_reset_iamthif_params(dev);
-               dev->wd_due_counter = 0;
-               dev->extra_write_index = 0;
-       }
-
-       dev->me_clients_num = 0;
-       dev->rd_msg_hdr = 0;
-       dev->stop = false;
-       dev->wd_pending = false;
-
-       /* update the state of the registers after reset */
-       dev->host_hw_state = mei_hcsr_read(dev);
-       dev->me_hw_state = mei_mecsr_read(dev);
-
-       dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
-           dev->host_hw_state, dev->me_hw_state);
-
-       if (unexpected)
-               dev_warn(&dev->pdev->dev, "unexpected reset.\n");
-
-       /* Wake up all readings so they can be interrupted */
-       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-               if (waitqueue_active(&cl_pos->rx_wait)) {
-                       dev_dbg(&dev->pdev->dev, "Waking up client!\n");
-                       wake_up_interruptible(&cl_pos->rx_wait);
-               }
-       }
-       /* remove all waiting requests */
-       list_for_each_entry_safe(cb_pos, cb_next,
-                       &dev->write_list.mei_cb.cb_list, cb_list) {
-               list_del(&cb_pos->cb_list);
-               mei_free_cb_private(cb_pos);
-       }
-}
-
-
-
-/**
- * host_start_message - mei host sends start message.
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_host_start_message(struct mei_device *dev)
-{
-       struct mei_msg_hdr *mei_hdr;
-       struct hbm_host_version_request *host_start_req;
-
-       /* host start message */
-       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-       mei_hdr->host_addr = 0;
-       mei_hdr->me_addr = 0;
-       mei_hdr->length = sizeof(struct hbm_host_version_request);
-       mei_hdr->msg_complete = 1;
-       mei_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->hbm_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 = false;
-       if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
-                                      mei_hdr->length)) {
-               dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
-               dev->mei_state = MEI_RESETING;
-               mei_reset(dev, 1);
-       }
-       dev->init_clients_state = MEI_START_MESSAGE;
-       dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
-       return ;
-}
-
-/**
- * host_enum_clients_message - host sends enumeration client request message.
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_host_enum_clients_message(struct mei_device *dev)
-{
-       struct mei_msg_hdr *mei_hdr;
-       struct hbm_host_enum_request *host_enum_req;
-       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-       /* enumerate clients */
-       mei_hdr->host_addr = 0;
-       mei_hdr->me_addr = 0;
-       mei_hdr->length = sizeof(struct hbm_host_enum_request);
-       mei_hdr->msg_complete = 1;
-       mei_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->hbm_cmd = HOST_ENUM_REQ_CMD;
-       if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
-                               mei_hdr->length)) {
-               dev->mei_state = MEI_RESETING;
-               dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
-               mei_reset(dev, 1);
-       }
-       dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
-       dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
-       return;
-}
-
-
-/**
- * allocate_me_clients_storage - allocates storage for me clients
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_allocate_me_clients_storage(struct mei_device *dev)
-{
-       struct mei_me_client *clients;
-       int b;
-
-       /* count how many ME clients we have */
-       for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
-               dev->me_clients_num++;
-
-       if (dev->me_clients_num <= 0)
-               return ;
-
-
-       if (dev->me_clients != NULL) {
-               kfree(dev->me_clients);
-               dev->me_clients = NULL;
-       }
-       dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
-               dev->me_clients_num * sizeof(struct mei_me_client));
-       /* allocate storage for ME clients representation */
-       clients = kcalloc(dev->me_clients_num,
-                       sizeof(struct mei_me_client), GFP_KERNEL);
-       if (!clients) {
-               dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
-               dev->mei_state = MEI_RESETING;
-               mei_reset(dev, 1);
-               return ;
-       }
-       dev->me_clients = clients;
-       return ;
-}
-/**
- * host_client_properties - reads properties for client
- *
- * @dev: the device structure
- *
- * returns:
- *     < 0 - Error.
- *  = 0 - no more clients.
- *  = 1 - still have clients to send properties request.
- */
-int mei_host_client_properties(struct mei_device *dev)
-{
-       struct mei_msg_hdr *mei_header;
-       struct hbm_props_request *host_cli_req;
-       int b;
-       u8 client_num = dev->me_client_presentation_num;
-
-       b = dev->me_client_index;
-       b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b);
-       if (b < MEI_CLIENTS_MAX) {
-               dev->me_clients[client_num].client_id = b;
-               dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
-               mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
-               mei_header->host_addr = 0;
-               mei_header->me_addr = 0;
-               mei_header->length = sizeof(struct hbm_props_request);
-               mei_header->msg_complete = 1;
-               mei_header->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->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
-               host_cli_req->address = b;
-
-               if (mei_write_message(dev, mei_header,
-                               (unsigned char *)host_cli_req,
-                               mei_header->length)) {
-                       dev->mei_state = MEI_RESETING;
-                       dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
-                       mei_reset(dev, 1);
-                       return -EIO;
-               }
-
-               dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
-               dev->me_client_index = b;
-               return 1;
-       }
-
-       return 0;
-}
-
-/**
- * mei_init_file_private - initializes private file structure.
- *
- * @priv: private file structure to be initialized
- * @file: the file structure
- */
-void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
-{
-       memset(priv, 0, sizeof(struct mei_cl));
-       init_waitqueue_head(&priv->wait);
-       init_waitqueue_head(&priv->rx_wait);
-       init_waitqueue_head(&priv->tx_wait);
-       INIT_LIST_HEAD(&priv->link);
-       priv->reading_state = MEI_IDLE;
-       priv->writing_state = MEI_IDLE;
-       priv->dev = dev;
-}
-
-int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
-{
-       int i, res = -1;
-
-       for (i = 0; i < dev->me_clients_num; ++i)
-               if (uuid_le_cmp(cuuid,
-                               dev->me_clients[i].props.protocol_name) == 0) {
-                       res = i;
-                       break;
-               }
-
-       return res;
-}
-
-
-/**
- * mei_find_me_client_update_filext - searches for ME client guid
- *                       sets client_id in mei_file_private if found
- * @dev: the device structure
- * @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
- */
-u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
-                               const uuid_le *cguid, u8 client_id)
-{
-       int i;
-
-       if (!dev || !priv || !cguid)
-               return 0;
-
-       /* check for valid client id */
-       i = mei_find_me_client_index(dev, *cguid);
-       if (i >= 0) {
-               priv->me_client_id = dev->me_clients[i].client_id;
-               priv->state = MEI_FILE_CONNECTING;
-               priv->host_client_id = client_id;
-
-               list_add_tail(&priv->link, &dev->file_list);
-               return (u8)i;
-       }
-
-       return 0;
-}
-
-/**
- * host_init_iamthif - mei initialization iamthif client.
- *
- * @dev: the device structure
- *
- */
-void mei_host_init_iamthif(struct mei_device *dev)
-{
-       u8 i;
-       unsigned char *msg_buf;
-
-       mei_cl_init(&dev->iamthif_cl, dev);
-       dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
-
-       /* find ME amthi client */
-       i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
-                           &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
-       if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
-               dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
-               return;
-       }
-
-       /* Assign iamthif_mtu to the value received from ME  */
-
-       dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
-       dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
-                       dev->me_clients[i].props.max_msg_length);
-
-       kfree(dev->iamthif_msg_buf);
-       dev->iamthif_msg_buf = NULL;
-
-       /* allocate storage for ME message buffer */
-       msg_buf = kcalloc(dev->iamthif_mtu,
-                       sizeof(unsigned char), GFP_KERNEL);
-       if (!msg_buf) {
-               dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n");
-               return;
-       }
-
-       dev->iamthif_msg_buf = msg_buf;
-
-       if (mei_connect(dev, &dev->iamthif_cl)) {
-               dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
-               dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
-               dev->iamthif_cl.host_client_id = 0;
-       } else {
-               dev->iamthif_cl.timer_count = CONNECT_TIMEOUT;
-       }
-}
-
-/**
- * mei_alloc_file_private - allocates a private file structure and sets it up.
- * @file: the file structure
- *
- * returns  The allocated file or NULL on failure
- */
-struct mei_cl *mei_cl_allocate(struct mei_device *dev)
-{
-       struct mei_cl *cl;
-
-       cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
-       if (!cl)
-               return NULL;
-
-       mei_cl_init(cl, dev);
-
-       return cl;
-}
-
-
-
-/**
- * mei_disconnect_host_client - sends disconnect message to fw from host client.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
-{
-       int rets, err;
-       long timeout = 15;      /* 15 seconds */
-       struct mei_cl_cb *cb;
-
-       if (!dev || !cl)
-               return -ENODEV;
-
-       if (cl->state != MEI_FILE_DISCONNECTING)
-               return 0;
-
-       cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
-       if (!cb)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&cb->cb_list);
-       cb->file_private = cl;
-       cb->major_file_operations = MEI_CLOSE;
-       if (dev->mei_host_buffer_is_empty) {
-               dev->mei_host_buffer_is_empty = false;
-               if (mei_disconnect(dev, cl)) {
-                       rets = -ENODEV;
-                       dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n");
-                       goto free;
-               }
-               mdelay(10); /* Wait for hardware disconnection ready */
-               list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list);
-       } else {
-               dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
-               list_add_tail(&cb->cb_list,
-                               &dev->ctrl_wr_list.mei_cb.cb_list);
-       }
-       mutex_unlock(&dev->device_lock);
-
-       err = wait_event_timeout(dev->wait_recvd_msg,
-                (MEI_FILE_DISCONNECTED == cl->state),
-                timeout * HZ);
-
-       mutex_lock(&dev->device_lock);
-       if (MEI_FILE_DISCONNECTED == cl->state) {
-               rets = 0;
-               dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
-       } else {
-               rets = -ENODEV;
-               if (MEI_FILE_DISCONNECTED != cl->state)
-                       dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
-
-               if (err)
-                       dev_dbg(&dev->pdev->dev,
-                                       "wait failed disconnect err=%08x\n",
-                                       err);
-
-               dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
-       }
-
-       mei_io_list_flush(&dev->ctrl_rd_list, cl);
-       mei_io_list_flush(&dev->ctrl_wr_list, cl);
-free:
-       mei_free_cb_private(cb);
-       return rets;
-}
-
-/**
- * mei_remove_client_from_file_list -
- *     removes file private data from device file list
- *
- * @dev: the device structure
- * @host_client_id: host client id to be removed
- */
-void mei_remove_client_from_file_list(struct mei_device *dev,
-                                      u8 host_client_id)
-{
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
-       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-               if (host_client_id == cl_pos->host_client_id) {
-                       dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
-                                       cl_pos->host_client_id,
-                                       cl_pos->me_client_id);
-                       list_del_init(&cl_pos->link);
-                       break;
-               }
-       }
-}
diff --git a/drivers/staging/mei/interface.c b/drivers/staging/mei/interface.c
deleted file mode 100644 (file)
index 9a2cfaf..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-#include <linux/pci.h>
-#include "mei_dev.h"
-#include "mei.h"
-#include "interface.h"
-
-
-
-/**
- * mei_set_csr_register - writes H_CSR register to the mei device,
- * and ignores the H_IS bit for it is write-one-to-zero.
- *
- * @dev: the device structure
- */
-void mei_hcsr_set(struct mei_device *dev)
-{
-       if ((dev->host_hw_state & H_IS) == H_IS)
-               dev->host_hw_state &= ~H_IS;
-       mei_reg_write(dev, H_CSR, dev->host_hw_state);
-       dev->host_hw_state = mei_hcsr_read(dev);
-}
-
-/**
- * mei_csr_enable_interrupts - enables mei device interrupts
- *
- * @dev: the device structure
- */
-void mei_enable_interrupts(struct mei_device *dev)
-{
-       dev->host_hw_state |= H_IE;
-       mei_hcsr_set(dev);
-}
-
-/**
- * mei_csr_disable_interrupts - disables mei device interrupts
- *
- * @dev: the device structure
- */
-void mei_disable_interrupts(struct mei_device *dev)
-{
-       dev->host_hw_state &= ~H_IE;
-       mei_hcsr_set(dev);
-}
-
-/**
- * _host_get_filled_slots - gets number of device filled buffer slots
- *
- * @device: the device structure
- *
- * returns number of filled slots
- */
-static unsigned char _host_get_filled_slots(const struct mei_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);
-}
-
-/**
- * mei_host_buffer_is_empty - checks if host buffer is empty.
- *
- * @dev: the device structure
- *
- * returns 1 if empty, 0 - otherwise.
- */
-int mei_host_buffer_is_empty(struct mei_device *dev)
-{
-       unsigned char filled_slots;
-
-       dev->host_hw_state = mei_hcsr_read(dev);
-       filled_slots = _host_get_filled_slots(dev);
-
-       if (filled_slots == 0)
-               return 1;
-
-       return 0;
-}
-
-/**
- * mei_count_empty_write_slots - counts write empty slots.
- *
- * @dev: the device structure
- *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
- */
-int mei_count_empty_write_slots(struct mei_device *dev)
-{
-       unsigned char buffer_depth, filled_slots, empty_slots;
-
-       dev->host_hw_state = mei_hcsr_read(dev);
-       buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
-       filled_slots = _host_get_filled_slots(dev);
-       empty_slots = buffer_depth - filled_slots;
-
-       /* check for overflow */
-       if (filled_slots > buffer_depth)
-               return -EOVERFLOW;
-
-       return empty_slots;
-}
-
-/**
- * mei_write_message - writes a message to mei device.
- *
- * @dev: the device structure
- * @header: header of message
- * @write_buffer: message buffer will be written
- * @write_length: message size will be written
- *
- * This function returns -EIO if write has failed
- */
-int mei_write_message(struct mei_device *dev,
-                     struct mei_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 = mei_hcsr_read(dev);
-
-       dev_dbg(&dev->pdev->dev,
-                       "host_hw_state = 0x%08x.\n",
-                       dev->host_hw_state);
-
-       dev_dbg(&dev->pdev->dev,
-                       "mei_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;
-       dev_dbg(&dev->pdev->dev,
-                       "filled = %hu, empty = %hu.\n",
-                       filled_slots, empty_slots);
-
-       dw_to_write = ((write_length + 3) / 4);
-
-       if (dw_to_write > empty_slots)
-               return -EIO;
-
-       mei_reg_write(dev, H_CB_WW, *((u32 *) header));
-
-       while (write_length >= 4) {
-               mei_reg_write(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);
-               mei_reg_write(dev, H_CB_WW, temp_msg);
-       }
-
-       dev->host_hw_state |= H_IG;
-       mei_hcsr_set(dev);
-       dev->me_hw_state = mei_mecsr_read(dev);
-       if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
-               return -EIO;
-
-       return 0;
-}
-
-/**
- * mei_count_full_read_slots - counts read full slots.
- *
- * @dev: the device structure
- *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
- */
-int mei_count_full_read_slots(struct mei_device *dev)
-{
-       char read_ptr, write_ptr;
-       unsigned char buffer_depth, filled_slots;
-
-       dev->me_hw_state = mei_mecsr_read(dev);
-       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);
-
-       /* check for overflow */
-       if (filled_slots > buffer_depth)
-               return -EOVERFLOW;
-
-       dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
-       return (int)filled_slots;
-}
-
-/**
- * mei_read_slots - reads a message from mei device.
- *
- * @dev: the device structure
- * @buffer: message buffer will be written
- * @buffer_length: message size will be read
- */
-void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
-                   unsigned long buffer_length)
-{
-       u32 *reg_buf = (u32 *)buffer;
-
-       for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
-               *reg_buf++ = mei_mecbrw_read(dev);
-
-       if (buffer_length > 0) {
-               u32 reg = mei_mecbrw_read(dev);
-               memcpy(reg_buf, &reg, buffer_length);
-       }
-
-       dev->host_hw_state |= H_IG;
-       mei_hcsr_set(dev);
-}
-
-/**
- * mei_flow_ctrl_creds - checks flow_control credentials.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
- *     -ENOENT if mei_cl is not present
- *     -EINVAL if single_recv_buf == 0
- */
-int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
-{
-       int i;
-
-       if (!dev->me_clients_num)
-               return 0;
-
-       if (cl->mei_flow_ctrl_creds > 0)
-               return 1;
-
-       for (i = 0; i < dev->me_clients_num; i++) {
-               struct mei_me_client  *me_cl = &dev->me_clients[i];
-               if (me_cl->client_id == cl->me_client_id) {
-                       if (me_cl->mei_flow_ctrl_creds) {
-                               if (WARN_ON(me_cl->props.single_recv_buf == 0))
-                                       return -EINVAL;
-                               return 1;
-                       } else {
-                               return 0;
-                       }
-               }
-       }
-       return -ENOENT;
-}
-
-/**
- * mei_flow_ctrl_reduce - reduces flow_control.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- * @returns
- *     0 on success
- *     -ENOENT when me client is not found
- *     -EINVAL when ctrl credits are <= 0
- */
-int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
-{
-       int i;
-
-       if (!dev->me_clients_num)
-               return -ENOENT;
-
-       for (i = 0; i < dev->me_clients_num; i++) {
-               struct mei_me_client  *me_cl = &dev->me_clients[i];
-               if (me_cl->client_id == cl->me_client_id) {
-                       if (me_cl->props.single_recv_buf != 0) {
-                               if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
-                                       return -EINVAL;
-                               dev->me_clients[i].mei_flow_ctrl_creds--;
-                       } else {
-                               if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
-                                       return -EINVAL;
-                               cl->mei_flow_ctrl_creds--;
-                       }
-                       return 0;
-               }
-       }
-       return -ENOENT;
-}
-
-/**
- * mei_send_flow_control - sends flow control to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
-{
-       struct mei_msg_hdr *mei_hdr;
-       struct hbm_flow_control *mei_flow_control;
-
-       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-       mei_hdr->host_addr = 0;
-       mei_hdr->me_addr = 0;
-       mei_hdr->length = sizeof(struct hbm_flow_control);
-       mei_hdr->msg_complete = 1;
-       mei_hdr->reserved = 0;
-
-       mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
-       memset(mei_flow_control, 0, sizeof(*mei_flow_control));
-       mei_flow_control->host_addr = cl->host_client_id;
-       mei_flow_control->me_addr = cl->me_client_id;
-       mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD;
-       memset(mei_flow_control->reserved, 0,
-                       sizeof(mei_flow_control->reserved));
-       dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
-               cl->host_client_id, cl->me_client_id);
-
-       return mei_write_message(dev, mei_hdr,
-                               (unsigned char *) mei_flow_control,
-                               sizeof(struct hbm_flow_control));
-}
-
-/**
- * mei_other_client_is_connecting - checks if other
- *    client with the same client id is connected.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * returns 1 if other client is connected, 0 - otherwise.
- */
-int mei_other_client_is_connecting(struct mei_device *dev,
-                               struct mei_cl *cl)
-{
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
-
-       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-               if ((cl_pos->state == MEI_FILE_CONNECTING) &&
-                       (cl_pos != cl) &&
-                       cl->me_client_id == cl_pos->me_client_id)
-                       return 1;
-
-       }
-       return 0;
-}
-
-/**
- * mei_disconnect - sends disconnect message to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
-{
-       struct mei_msg_hdr *mei_hdr;
-       struct hbm_client_disconnect_request *mei_cli_disconnect;
-
-       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-       mei_hdr->host_addr = 0;
-       mei_hdr->me_addr = 0;
-       mei_hdr->length = sizeof(struct hbm_client_disconnect_request);
-       mei_hdr->msg_complete = 1;
-       mei_hdr->reserved = 0;
-
-       mei_cli_disconnect =
-           (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
-       memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect));
-       mei_cli_disconnect->host_addr = cl->host_client_id;
-       mei_cli_disconnect->me_addr = cl->me_client_id;
-       mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
-       mei_cli_disconnect->reserved[0] = 0;
-
-       return mei_write_message(dev, mei_hdr,
-                               (unsigned char *) mei_cli_disconnect,
-                               sizeof(struct hbm_client_disconnect_request));
-}
-
-/**
- * mei_connect - sends connect message to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_connect(struct mei_device *dev, struct mei_cl *cl)
-{
-       struct mei_msg_hdr *mei_hdr;
-       struct hbm_client_connect_request *mei_cli_connect;
-
-       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-       mei_hdr->host_addr = 0;
-       mei_hdr->me_addr = 0;
-       mei_hdr->length = sizeof(struct hbm_client_connect_request);
-       mei_hdr->msg_complete = 1;
-       mei_hdr->reserved = 0;
-
-       mei_cli_connect =
-           (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
-       mei_cli_connect->host_addr = cl->host_client_id;
-       mei_cli_connect->me_addr = cl->me_client_id;
-       mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
-       mei_cli_connect->reserved = 0;
-
-       return mei_write_message(dev, mei_hdr,
-                               (unsigned char *) mei_cli_connect,
-                               sizeof(struct hbm_client_connect_request));
-}
diff --git a/drivers/staging/mei/interface.h b/drivers/staging/mei/interface.h
deleted file mode 100644 (file)
index 0d00435..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-
-
-#ifndef _MEI_INTERFACE_H_
-#define _MEI_INTERFACE_H_
-
-#include "mei.h"
-#include "mei_dev.h"
-
-
-#define AMT_WD_DEFAULT_TIMEOUT 120     /* seconds */
-#define AMT_WD_MIN_TIMEOUT 120 /* seconds */
-#define AMT_WD_MAX_TIMEOUT 65535       /* seconds */
-
-#define MEI_WATCHDOG_DATA_SIZE         16
-#define MEI_START_WD_DATA_SIZE         20
-#define MEI_WD_PARAMS_SIZE             4
-
-
-void mei_read_slots(struct mei_device *dev,
-                    unsigned char *buffer,
-                    unsigned long buffer_length);
-
-int mei_write_message(struct mei_device *dev,
-                            struct mei_msg_hdr *header,
-                            unsigned char *write_buffer,
-                            unsigned long write_length);
-
-int mei_host_buffer_is_empty(struct mei_device *dev);
-
-int mei_count_full_read_slots(struct mei_device *dev);
-
-int mei_count_empty_write_slots(struct mei_device *dev);
-
-int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
-
-int mei_wd_send(struct mei_device *dev);
-int mei_wd_stop(struct mei_device *dev, bool preserve);
-int mei_wd_host_init(struct mei_device *dev);
-/*
- * mei_watchdog_register  - Registering watchdog interface
- *   once we got connection to the WD Client
- * @dev - mei device
- */
-void mei_watchdog_register(struct mei_device *dev);
-/*
- * mei_watchdog_unregister  - Unregistering watchdog interface
- * @dev - mei device
- */
-void mei_watchdog_unregister(struct mei_device *dev);
-
-int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl);
-
-int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl);
-
-int mei_disconnect(struct mei_device *dev, struct mei_cl *cl);
-int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl);
-int mei_connect(struct mei_device *dev, struct mei_cl *cl);
-
-#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/staging/mei/interrupt.c b/drivers/staging/mei/interrupt.c
deleted file mode 100644 (file)
index 2007d24..0000000
+++ /dev/null
@@ -1,1590 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-
-#include <linux/pci.h>
-#include <linux/kthread.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/jiffies.h>
-
-#include "mei_dev.h"
-#include "mei.h"
-#include "hw.h"
-#include "interface.h"
-
-
-/**
- * mei_interrupt_quick_handler - The ISR of the MEI device
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- */
-irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
-{
-       struct mei_device *dev = (struct mei_device *) dev_id;
-       u32 csr_reg = mei_hcsr_read(dev);
-
-       if ((csr_reg & H_IS) != H_IS)
-               return IRQ_NONE;
-
-       /* clear H_IS bit in H_CSR */
-       mei_reg_write(dev, H_CSR, csr_reg);
-
-       return IRQ_WAKE_THREAD;
-}
-
-/**
- * _mei_cmpl - processes completed operation.
- *
- * @cl: private data of the file object.
- * @cb_pos: callback block.
- */
-static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
-{
-       if (cb_pos->major_file_operations == MEI_WRITE) {
-               mei_free_cb_private(cb_pos);
-               cb_pos = NULL;
-               cl->writing_state = MEI_WRITE_COMPLETE;
-               if (waitqueue_active(&cl->tx_wait))
-                       wake_up_interruptible(&cl->tx_wait);
-
-       } else if (cb_pos->major_file_operations == MEI_READ &&
-                       MEI_READING == cl->reading_state) {
-               cl->reading_state = MEI_READ_COMPLETE;
-               if (waitqueue_active(&cl->rx_wait))
-                       wake_up_interruptible(&cl->rx_wait);
-
-       }
-}
-
-/**
- * _mei_cmpl_iamthif - processes completed iamthif operation.
- *
- * @dev: the device structure.
- * @cb_pos: callback block.
- */
-static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos)
-{
-       if (dev->iamthif_canceled != 1) {
-               dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
-               dev->iamthif_stall_timer = 0;
-               memcpy(cb_pos->response_buffer.data,
-                               dev->iamthif_msg_buf,
-                               dev->iamthif_msg_buf_index);
-               list_add_tail(&cb_pos->cb_list,
-                               &dev->amthi_read_complete_list.mei_cb.cb_list);
-               dev_dbg(&dev->pdev->dev, "amthi read completed.\n");
-               dev->iamthif_timer = jiffies;
-               dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
-                               dev->iamthif_timer);
-       } else {
-               mei_run_next_iamthif_cmd(dev);
-       }
-
-       dev_dbg(&dev->pdev->dev, "completing amthi call back.\n");
-       wake_up_interruptible(&dev->iamthif_cl.wait);
-}
-
-
-/**
- * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to
- * handle the read amthi message data processing.
- *
- * @complete_list: An instance of our list structure
- * @dev: the device structure
- * @mei_hdr: header of amthi message
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list,
-               struct mei_device *dev,
-               struct mei_msg_hdr *mei_hdr)
-{
-       struct mei_cl *cl;
-       struct mei_cl_cb *cb;
-       unsigned char *buffer;
-
-       BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
-       BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
-
-       buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
-       BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
-
-       mei_read_slots(dev, buffer, mei_hdr->length);
-
-       dev->iamthif_msg_buf_index += mei_hdr->length;
-
-       if (!mei_hdr->msg_complete)
-               return 0;
-
-       dev_dbg(&dev->pdev->dev,
-                       "amthi_message_buffer_index =%d\n",
-                       mei_hdr->length);
-
-       dev_dbg(&dev->pdev->dev, "completed amthi read.\n ");
-       if (!dev->iamthif_current_cb)
-               return -ENODEV;
-
-       cb = dev->iamthif_current_cb;
-       dev->iamthif_current_cb = NULL;
-
-       cl = (struct mei_cl *)cb->file_private;
-       if (!cl)
-               return -ENODEV;
-
-       dev->iamthif_stall_timer = 0;
-       cb->information =       dev->iamthif_msg_buf_index;
-       cb->read_time = jiffies;
-       if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) {
-               /* found the iamthif cb */
-               dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n ");
-               dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n ");
-               list_add_tail(&cb->cb_list,
-                                               &complete_list->mei_cb.cb_list);
-       }
-       return 0;
-}
-
-/**
- * _mei_irq_thread_state_ok - checks if mei header matches file private data
- *
- * @cl: private data of the file object
- * @mei_hdr: header of mei client message
- *
- * returns !=0 if matches, 0 if no match.
- */
-static int _mei_irq_thread_state_ok(struct mei_cl *cl,
-                               struct mei_msg_hdr *mei_hdr)
-{
-       return (cl->host_client_id == mei_hdr->host_addr &&
-               cl->me_client_id == mei_hdr->me_addr &&
-               cl->state == MEI_FILE_CONNECTED &&
-               MEI_READ_COMPLETE != cl->reading_state);
-}
-
-/**
- * mei_irq_thread_read_client_message - bottom half read routine after ISR to
- * handle the read mei client message data processing.
- *
- * @complete_list: An instance of our list structure
- * @dev: the device structure
- * @mei_hdr: header of mei client message
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
-               struct mei_device *dev,
-               struct mei_msg_hdr *mei_hdr)
-{
-       struct mei_cl *cl;
-       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-       unsigned char *buffer = NULL;
-
-       dev_dbg(&dev->pdev->dev, "start client msg\n");
-       if (list_empty(&dev->read_list.mei_cb.cb_list))
-               goto quit;
-
-       list_for_each_entry_safe(cb_pos, cb_next,
-                       &dev->read_list.mei_cb.cb_list, cb_list) {
-               cl = (struct mei_cl *)cb_pos->file_private;
-               if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
-                       cl->reading_state = MEI_READING;
-                       buffer = cb_pos->response_buffer.data + cb_pos->information;
-
-                       if (cb_pos->response_buffer.size <
-                                       mei_hdr->length + cb_pos->information) {
-                               dev_dbg(&dev->pdev->dev, "message overflow.\n");
-                               list_del(&cb_pos->cb_list);
-                               return -ENOMEM;
-                       }
-                       if (buffer)
-                               mei_read_slots(dev, buffer, mei_hdr->length);
-
-                       cb_pos->information += mei_hdr->length;
-                       if (mei_hdr->msg_complete) {
-                               cl->status = 0;
-                               list_del(&cb_pos->cb_list);
-                               dev_dbg(&dev->pdev->dev,
-                                       "completed read host client = %d,"
-                                       "ME client = %d, "
-                                       "data length = %lu\n",
-                                       cl->host_client_id,
-                                       cl->me_client_id,
-                                       cb_pos->information);
-
-                               *(cb_pos->response_buffer.data +
-                                       cb_pos->information) = '\0';
-                               dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n",
-                                       cb_pos->response_buffer.data);
-                               list_add_tail(&cb_pos->cb_list,
-                                       &complete_list->mei_cb.cb_list);
-                       }
-
-                       break;
-               }
-
-       }
-
-quit:
-       dev_dbg(&dev->pdev->dev, "message read\n");
-       if (!buffer) {
-               mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
-               dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
-                               *(u32 *) dev->rd_msg_buf);
-       }
-
-       return 0;
-}
-
-/**
- * _mei_irq_thread_iamthif_read - prepares to read iamthif data.
- *
- * @dev: the device structure.
- * @slots: free slots.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
-{
-
-       if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
-                       + sizeof(struct hbm_flow_control))) {
-               return -EMSGSIZE;
-       }
-       *slots -= (sizeof(struct mei_msg_hdr) +
-                               sizeof(struct hbm_flow_control) + 3) / 4;
-       if (mei_send_flow_control(dev, &dev->iamthif_cl)) {
-               dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
-               return -EIO;
-       }
-
-       dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
-       dev->iamthif_state = MEI_IAMTHIF_READING;
-       dev->iamthif_flow_control_pending = false;
-       dev->iamthif_msg_buf_index = 0;
-       dev->iamthif_msg_buf_size = 0;
-       dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
-       dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
-       return 0;
-}
-
-/**
- * _mei_irq_thread_close - processes close related operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
-                               struct mei_cl_cb *cb_pos,
-                               struct mei_cl *cl,
-                               struct mei_io_list *cmpl_list)
-{
-       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_client_disconnect_request))) {
-               *slots -= (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_client_disconnect_request) + 3) / 4;
-
-               if (mei_disconnect(dev, cl)) {
-                       cl->status = 0;
-                       cb_pos->information = 0;
-                       list_move_tail(&cb_pos->cb_list,
-                                       &cmpl_list->mei_cb.cb_list);
-                       return -EMSGSIZE;
-               } else {
-                       cl->state = MEI_FILE_DISCONNECTING;
-                       cl->status = 0;
-                       cb_pos->information = 0;
-                       list_move_tail(&cb_pos->cb_list,
-                                       &dev->ctrl_rd_list.mei_cb.cb_list);
-                       cl->timer_count = MEI_CONNECT_TIMEOUT;
-               }
-       } else {
-               /* return the cancel routine */
-               return -EBADMSG;
-       }
-
-       return 0;
-}
-
-/**
- * is_treat_specially_client - checks if the message belongs
- * to the file private data.
- *
- * @cl: private data of the file object
- * @rs: connect response bus message
- *
- */
-static bool is_treat_specially_client(struct mei_cl *cl,
-               struct hbm_client_connect_response *rs)
-{
-
-       if (cl->host_client_id == rs->host_addr &&
-           cl->me_client_id == rs->me_addr) {
-               if (!rs->status) {
-                       cl->state = MEI_FILE_CONNECTED;
-                       cl->status = 0;
-
-               } else {
-                       cl->state = MEI_FILE_DISCONNECTED;
-                       cl->status = -ENODEV;
-               }
-               cl->timer_count = 0;
-
-               return true;
-       }
-       return false;
-}
-
-/**
- * mei_client_connect_response - connects to response irq routine
- *
- * @dev: the device structure
- * @rs: connect response bus message
- */
-static void mei_client_connect_response(struct mei_device *dev,
-               struct hbm_client_connect_response *rs)
-{
-
-       struct mei_cl *cl;
-       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-
-       dev_dbg(&dev->pdev->dev,
-                       "connect_response:\n"
-                       "ME Client = %d\n"
-                       "Host Client = %d\n"
-                       "Status = %d\n",
-                       rs->me_addr,
-                       rs->host_addr,
-                       rs->status);
-
-       /* if WD or iamthif client treat specially */
-
-       if (is_treat_specially_client(&(dev->wd_cl), rs)) {
-               dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
-               mei_watchdog_register(dev);
-
-               /* next step in the state maching */
-               mei_host_init_iamthif(dev);
-               return;
-       }
-
-       if (is_treat_specially_client(&(dev->iamthif_cl), rs)) {
-               dev->iamthif_state = MEI_IAMTHIF_IDLE;
-               return;
-       }
-       list_for_each_entry_safe(cb_pos, cb_next,
-                               &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
-
-               cl = (struct mei_cl *)cb_pos->file_private;
-               if (!cl) {
-                       list_del(&cb_pos->cb_list);
-                       return;
-               }
-               if (MEI_IOCTL == cb_pos->major_file_operations) {
-                       if (is_treat_specially_client(cl, rs)) {
-                               list_del(&cb_pos->cb_list);
-                               cl->status = 0;
-                               cl->timer_count = 0;
-                               break;
-                       }
-               }
-       }
-}
-
-/**
- * mei_client_disconnect_response - disconnects from response irq routine
- *
- * @dev: the device structure
- * @rs: disconnect response bus message
- */
-static void mei_client_disconnect_response(struct mei_device *dev,
-                                       struct hbm_client_connect_response *rs)
-{
-       struct mei_cl *cl;
-       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-
-       dev_dbg(&dev->pdev->dev,
-                       "disconnect_response:\n"
-                       "ME Client = %d\n"
-                       "Host Client = %d\n"
-                       "Status = %d\n",
-                       rs->me_addr,
-                       rs->host_addr,
-                       rs->status);
-
-       list_for_each_entry_safe(cb_pos, cb_next,
-                       &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
-               cl = (struct mei_cl *)cb_pos->file_private;
-
-               if (!cl) {
-                       list_del(&cb_pos->cb_list);
-                       return;
-               }
-
-               dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
-               if (cl->host_client_id == rs->host_addr &&
-                   cl->me_client_id == rs->me_addr) {
-
-                       list_del(&cb_pos->cb_list);
-                       if (!rs->status)
-                               cl->state = MEI_FILE_DISCONNECTED;
-
-                       cl->status = 0;
-                       cl->timer_count = 0;
-                       break;
-               }
-       }
-}
-
-/**
- * same_flow_addr - tells if they have the same address.
- *
- * @file: private data of the file object.
- * @flow: flow control.
- *
- * returns  !=0, same; 0,not.
- */
-static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow)
-{
-       return (cl->host_client_id == flow->host_addr &&
-               cl->me_client_id == flow->me_addr);
-}
-
-/**
- * add_single_flow_creds - adds single buffer credentials.
- *
- * @file: private data ot the file object.
- * @flow: flow control.
- */
-static void add_single_flow_creds(struct mei_device *dev,
-                                 struct hbm_flow_control *flow)
-{
-       struct mei_me_client *client;
-       int i;
-
-       for (i = 0; i < dev->me_clients_num; i++) {
-               client = &dev->me_clients[i];
-               if (client && flow->me_addr == client->client_id) {
-                       if (client->props.single_recv_buf) {
-                               client->mei_flow_ctrl_creds++;
-                               dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
-                                   flow->me_addr);
-                               dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
-                                   client->mei_flow_ctrl_creds);
-                       } else {
-                               BUG();  /* error in flow control */
-                       }
-               }
-       }
-}
-
-/**
- * mei_client_flow_control_response - flow control response irq routine
- *
- * @dev: the device structure
- * @flow_control: flow control response bus message
- */
-static void mei_client_flow_control_response(struct mei_device *dev,
-               struct hbm_flow_control *flow_control)
-{
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
-
-       if (!flow_control->host_addr) {
-               /* single receive buffer */
-               add_single_flow_creds(dev, flow_control);
-       } else {
-               /* normal connection */
-               list_for_each_entry_safe(cl_pos, cl_next,
-                               &dev->file_list, link) {
-                       dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n");
-
-                       dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n",
-                           cl_pos->host_client_id,
-                           cl_pos->me_client_id);
-                       dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
-                           flow_control->host_addr,
-                           flow_control->me_addr);
-                       if (same_flow_addr(cl_pos, flow_control)) {
-                               dev_dbg(&dev->pdev->dev, "recv ctrl msg for host  %d ME %d.\n",
-                                   flow_control->host_addr,
-                                   flow_control->me_addr);
-                               cl_pos->mei_flow_ctrl_creds++;
-                               dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
-                                   cl_pos->mei_flow_ctrl_creds);
-                               break;
-                       }
-               }
-       }
-}
-
-/**
- * same_disconn_addr - tells if they have the same address
- *
- * @file: private data of the file object.
- * @disconn: disconnection request.
- *
- * returns !=0, same; 0,not.
- */
-static int same_disconn_addr(struct mei_cl *cl,
-                            struct hbm_client_disconnect_request *disconn)
-{
-       return (cl->host_client_id == disconn->host_addr &&
-               cl->me_client_id == disconn->me_addr);
-}
-
-/**
- * mei_client_disconnect_request - disconnects from request irq routine
- *
- * @dev: the device structure.
- * @disconnect_req: disconnect request bus message.
- */
-static void mei_client_disconnect_request(struct mei_device *dev,
-               struct hbm_client_disconnect_request *disconnect_req)
-{
-       struct mei_msg_hdr *mei_hdr;
-       struct hbm_client_connect_response *disconnect_res;
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
-
-       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-               if (same_disconn_addr(cl_pos, disconnect_req)) {
-                       dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
-                                       disconnect_req->host_addr,
-                                       disconnect_req->me_addr);
-                       cl_pos->state = MEI_FILE_DISCONNECTED;
-                       cl_pos->timer_count = 0;
-                       if (cl_pos == &dev->wd_cl) {
-                               dev->wd_due_counter = 0;
-                               dev->wd_pending = false;
-                       } else if (cl_pos == &dev->iamthif_cl)
-                               dev->iamthif_timer = 0;
-
-                       /* prepare disconnect response */
-                       mei_hdr =
-                               (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
-                       mei_hdr->host_addr = 0;
-                       mei_hdr->me_addr = 0;
-                       mei_hdr->length =
-                               sizeof(struct hbm_client_connect_response);
-                       mei_hdr->msg_complete = 1;
-                       mei_hdr->reserved = 0;
-
-                       disconnect_res =
-                               (struct hbm_client_connect_response *)
-                               &dev->ext_msg_buf[1];
-                       disconnect_res->host_addr = cl_pos->host_client_id;
-                       disconnect_res->me_addr = cl_pos->me_client_id;
-                       disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
-                       disconnect_res->status = 0;
-                       dev->extra_write_index = 2;
-                       break;
-               }
-       }
-}
-
-
-/**
- * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
- * handle the read bus message cmd processing.
- *
- * @dev: the device structure
- * @mei_hdr: header of bus message
- */
-static void mei_irq_thread_read_bus_message(struct mei_device *dev,
-               struct mei_msg_hdr *mei_hdr)
-{
-       struct mei_bus_message *mei_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 *host_stop_req;
-       int res;
-
-
-       /* read the message to our buffer */
-       BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
-       mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
-       mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
-
-       switch (mei_msg->hbm_cmd) {
-       case HOST_START_RES_CMD:
-               version_res = (struct hbm_host_version_response *) mei_msg;
-               if (version_res->host_version_supported) {
-                       dev->version.major_version = HBM_MAJOR_VERSION;
-                       dev->version.minor_version = HBM_MINOR_VERSION;
-                       if (dev->mei_state == MEI_INIT_CLIENTS &&
-                           dev->init_clients_state == MEI_START_MESSAGE) {
-                               dev->init_clients_timer = 0;
-                               mei_host_enum_clients_message(dev);
-                       } else {
-                               dev->recvd_msg = false;
-                               dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
-                               mei_reset(dev, 1);
-                               return;
-                       }
-               } else {
-                       dev->version = version_res->me_max_version;
-                       /* send stop message */
-                       mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
-                       mei_hdr->host_addr = 0;
-                       mei_hdr->me_addr = 0;
-                       mei_hdr->length = sizeof(struct hbm_host_stop_request);
-                       mei_hdr->msg_complete = 1;
-                       mei_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->hbm_cmd = HOST_STOP_REQ_CMD;
-                       host_stop_req->reason = DRIVER_STOP_REQUEST;
-                       mei_write_message(dev, mei_hdr,
-                                          (unsigned char *) (host_stop_req),
-                                          mei_hdr->length);
-                       dev_dbg(&dev->pdev->dev, "version mismatch.\n");
-                       return;
-               }
-
-               dev->recvd_msg = true;
-               dev_dbg(&dev->pdev->dev, "host start response message received.\n");
-               break;
-
-       case CLIENT_CONNECT_RES_CMD:
-               connect_res =
-                       (struct hbm_client_connect_response *) mei_msg;
-               mei_client_connect_response(dev, connect_res);
-               dev_dbg(&dev->pdev->dev, "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 *) mei_msg;
-               mei_client_disconnect_response(dev, disconnect_res);
-               dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
-               wake_up(&dev->wait_recvd_msg);
-               break;
-
-       case MEI_FLOW_CONTROL_CMD:
-               flow_control = (struct hbm_flow_control *) mei_msg;
-               mei_client_flow_control_response(dev, flow_control);
-               dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
-               break;
-
-       case HOST_CLIENT_PROPERTIES_RES_CMD:
-               props_res = (struct hbm_props_response *)mei_msg;
-               if (props_res->status || !dev->me_clients) {
-                       dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
-                       mei_reset(dev, 1);
-                       return;
-               }
-               if (dev->me_clients[dev->me_client_presentation_num]
-                                       .client_id == props_res->address) {
-
-                       dev->me_clients[dev->me_client_presentation_num].props
-                                               = props_res->client_properties;
-
-                       if (dev->mei_state == MEI_INIT_CLIENTS &&
-                           dev->init_clients_state ==
-                                       MEI_CLIENT_PROPERTIES_MESSAGE) {
-                               dev->me_client_index++;
-                               dev->me_client_presentation_num++;
-
-                               /** Send Client Properties request **/
-                               res = mei_host_client_properties(dev);
-                               if (res < 0) {
-                                       dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed");
-                                       return;
-                               } else if (!res) {
-                                       /*
-                                        * No more clients to send to.
-                                        * Clear Map for indicating now ME clients
-                                        * with associated host client
-                                        */
-                                       bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
-                                       dev->open_handle_count = 0;
-
-                                       /*
-                                        * Reserving the first three client IDs
-                                        * Client Id 0 - Reserved for MEI Bus Message communications
-                                        * Client Id 1 - Reserved for Watchdog
-                                        * Client ID 2 - Reserved for AMTHI
-                                        */
-                                       bitmap_set(dev->host_clients_map, 0, 3);
-                                       dev->mei_state = MEI_ENABLED;
-
-                                       /* if wd initialization fails, initialization the AMTHI client,
-                                        * otherwise the AMTHI client will be initialized after the WD client connect response
-                                        * will be received
-                                        */
-                                       if (mei_wd_host_init(dev))
-                                               mei_host_init_iamthif(dev);
-                               }
-
-                       } else {
-                               dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message");
-                               mei_reset(dev, 1);
-                               return;
-                       }
-               } else {
-                       dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n");
-                       mei_reset(dev, 1);
-                       return;
-               }
-               break;
-
-       case HOST_ENUM_RES_CMD:
-               enum_res = (struct hbm_host_enum_response *) mei_msg;
-               memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
-               if (dev->mei_state == MEI_INIT_CLIENTS &&
-                   dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
-                               dev->init_clients_timer = 0;
-                               dev->me_client_presentation_num = 0;
-                               dev->me_client_index = 0;
-                               mei_allocate_me_clients_storage(dev);
-                               dev->init_clients_state =
-                                       MEI_CLIENT_PROPERTIES_MESSAGE;
-                               mei_host_client_properties(dev);
-               } else {
-                       dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
-                       mei_reset(dev, 1);
-                       return;
-               }
-               break;
-
-       case HOST_STOP_RES_CMD:
-               dev->mei_state = MEI_DISABLED;
-               dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
-               mei_reset(dev, 1);
-               break;
-
-       case CLIENT_DISCONNECT_REQ_CMD:
-               /* search for client */
-               disconnect_req =
-                       (struct hbm_client_disconnect_request *) mei_msg;
-               mei_client_disconnect_request(dev, disconnect_req);
-               break;
-
-       case ME_STOP_REQ_CMD:
-               /* prepare stop request */
-               mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
-               mei_hdr->host_addr = 0;
-               mei_hdr->me_addr = 0;
-               mei_hdr->length = sizeof(struct hbm_host_stop_request);
-               mei_hdr->msg_complete = 1;
-               mei_hdr->reserved = 0;
-               host_stop_req =
-                       (struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
-               memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
-               host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
-               host_stop_req->reason = DRIVER_STOP_REQUEST;
-               host_stop_req->reserved[0] = 0;
-               host_stop_req->reserved[1] = 0;
-               dev->extra_write_index = 2;
-               break;
-
-       default:
-               BUG();
-               break;
-
-       }
-}
-
-
-/**
- * _mei_hb_read - processes read related operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_read(struct mei_device *dev,        s32 *slots,
-                       struct mei_cl_cb *cb_pos,
-                       struct mei_cl *cl,
-                       struct mei_io_list *cmpl_list)
-{
-       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_flow_control))) {
-               /* return the cancel routine */
-               list_del(&cb_pos->cb_list);
-               return -EBADMSG;
-       }
-
-       *slots -= (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_flow_control) + 3) / 4;
-       if (mei_send_flow_control(dev, cl)) {
-               cl->status = -ENODEV;
-               cb_pos->information = 0;
-               list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list);
-               return -ENODEV;
-       }
-       list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list);
-
-       return 0;
-}
-
-
-/**
- * _mei_irq_thread_ioctl - processes ioctl related operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
-                       struct mei_cl_cb *cb_pos,
-                       struct mei_cl *cl,
-                       struct mei_io_list *cmpl_list)
-{
-       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_client_connect_request))) {
-               cl->state = MEI_FILE_CONNECTING;
-               *slots -= (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_client_connect_request) + 3) / 4;
-               if (mei_connect(dev, cl)) {
-                       cl->status = -ENODEV;
-                       cb_pos->information = 0;
-                       list_del(&cb_pos->cb_list);
-                       return -ENODEV;
-               } else {
-                       list_move_tail(&cb_pos->cb_list,
-                               &dev->ctrl_rd_list.mei_cb.cb_list);
-                       cl->timer_count = MEI_CONNECT_TIMEOUT;
-               }
-       } else {
-               /* return the cancel routine */
-               list_del(&cb_pos->cb_list);
-               return -EBADMSG;
-       }
-
-       return 0;
-}
-
-/**
- * _mei_irq_thread_cmpl - processes completed and no-iamthif operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_cmpl(struct mei_device *dev,        s32 *slots,
-                       struct mei_cl_cb *cb_pos,
-                       struct mei_cl *cl,
-                       struct mei_io_list *cmpl_list)
-{
-       struct mei_msg_hdr *mei_hdr;
-
-       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-                       (cb_pos->request_buffer.size -
-                       cb_pos->information))) {
-               mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-               mei_hdr->host_addr = cl->host_client_id;
-               mei_hdr->me_addr = cl->me_client_id;
-               mei_hdr->length = cb_pos->request_buffer.size -
-                                       cb_pos->information;
-               mei_hdr->msg_complete = 1;
-               mei_hdr->reserved = 0;
-               dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d"
-                       "mei_hdr->msg_complete = %d\n",
-                               cb_pos->request_buffer.size,
-                               mei_hdr->msg_complete);
-               dev_dbg(&dev->pdev->dev, "cb_pos->information  =%lu\n",
-                               cb_pos->information);
-               dev_dbg(&dev->pdev->dev, "mei_hdr->length  =%d\n",
-                               mei_hdr->length);
-               *slots -= (sizeof(struct mei_msg_hdr) +
-                               mei_hdr->length + 3) / 4;
-               if (mei_write_message(dev, mei_hdr,
-                               (unsigned char *)
-                               (cb_pos->request_buffer.data +
-                               cb_pos->information),
-                               mei_hdr->length)) {
-                       cl->status = -ENODEV;
-                       list_move_tail(&cb_pos->cb_list,
-                               &cmpl_list->mei_cb.cb_list);
-                       return -ENODEV;
-               } else {
-                       if (mei_flow_ctrl_reduce(dev, cl))
-                               return -ENODEV;
-                       cl->status = 0;
-                       cb_pos->information += mei_hdr->length;
-                       list_move_tail(&cb_pos->cb_list,
-                               &dev->write_waiting_list.mei_cb.cb_list);
-               }
-       } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
-               /* buffer is still empty */
-               mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-               mei_hdr->host_addr = cl->host_client_id;
-               mei_hdr->me_addr = cl->me_client_id;
-               mei_hdr->length =
-                       (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
-               mei_hdr->msg_complete = 0;
-               mei_hdr->reserved = 0;
-
-               (*slots) -= (sizeof(struct mei_msg_hdr) +
-                               mei_hdr->length + 3) / 4;
-               if (mei_write_message(dev, mei_hdr,
-                                       (unsigned char *)
-                                       (cb_pos->request_buffer.data +
-                                       cb_pos->information),
-                                       mei_hdr->length)) {
-                       cl->status = -ENODEV;
-                       list_move_tail(&cb_pos->cb_list,
-                               &cmpl_list->mei_cb.cb_list);
-                       return -ENODEV;
-               } else {
-                       cb_pos->information += mei_hdr->length;
-                       dev_dbg(&dev->pdev->dev,
-                                       "cb_pos->request_buffer.size =%d"
-                                       " mei_hdr->msg_complete = %d\n",
-                                       cb_pos->request_buffer.size,
-                                       mei_hdr->msg_complete);
-                       dev_dbg(&dev->pdev->dev, "cb_pos->information  =%lu\n",
-                                       cb_pos->information);
-                       dev_dbg(&dev->pdev->dev, "mei_hdr->length  =%d\n",
-                                       mei_hdr->length);
-               }
-               return -EMSGSIZE;
-       } else {
-               return -EBADMSG;
-       }
-
-       return 0;
-}
-
-/**
- * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation.
- *
- * @dev: the device structure.
- * @slots: free slots.
- * @cb_pos: callback block.
- * @cl: private data of the file object.
- * @cmpl_list: complete list.
- *
- * returns 0, OK; otherwise, error.
- */
-static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots,
-                       struct mei_cl_cb *cb_pos,
-                       struct mei_cl *cl,
-                       struct mei_io_list *cmpl_list)
-{
-       struct mei_msg_hdr *mei_hdr;
-
-       if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
-                       dev->iamthif_msg_buf_size -
-                       dev->iamthif_msg_buf_index)) {
-               mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-               mei_hdr->host_addr = cl->host_client_id;
-               mei_hdr->me_addr = cl->me_client_id;
-               mei_hdr->length = dev->iamthif_msg_buf_size -
-                       dev->iamthif_msg_buf_index;
-               mei_hdr->msg_complete = 1;
-               mei_hdr->reserved = 0;
-
-               *slots -= (sizeof(struct mei_msg_hdr) +
-                               mei_hdr->length + 3) / 4;
-
-               if (mei_write_message(dev, mei_hdr,
-                                       (dev->iamthif_msg_buf +
-                                       dev->iamthif_msg_buf_index),
-                                       mei_hdr->length)) {
-                       dev->iamthif_state = MEI_IAMTHIF_IDLE;
-                       cl->status = -ENODEV;
-                       list_del(&cb_pos->cb_list);
-                       return -ENODEV;
-               } else {
-                       if (mei_flow_ctrl_reduce(dev, cl))
-                               return -ENODEV;
-                       dev->iamthif_msg_buf_index += mei_hdr->length;
-                       cb_pos->information = dev->iamthif_msg_buf_index;
-                       cl->status = 0;
-                       dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
-                       dev->iamthif_flow_control_pending = true;
-                       /* save iamthif cb sent to amthi client */
-                       dev->iamthif_current_cb = cb_pos;
-                       list_move_tail(&cb_pos->cb_list,
-                               &dev->write_waiting_list.mei_cb.cb_list);
-
-               }
-       } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
-                       /* buffer is still empty */
-               mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-               mei_hdr->host_addr = cl->host_client_id;
-               mei_hdr->me_addr = cl->me_client_id;
-               mei_hdr->length =
-                       (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
-               mei_hdr->msg_complete = 0;
-               mei_hdr->reserved = 0;
-
-               *slots -= (sizeof(struct mei_msg_hdr) +
-                               mei_hdr->length + 3) / 4;
-
-               if (mei_write_message(dev, mei_hdr,
-                                       (dev->iamthif_msg_buf +
-                                       dev->iamthif_msg_buf_index),
-                                       mei_hdr->length)) {
-                       cl->status = -ENODEV;
-                       list_del(&cb_pos->cb_list);
-               } else {
-                       dev->iamthif_msg_buf_index += mei_hdr->length;
-               }
-               return -EMSGSIZE;
-       } else {
-               return -EBADMSG;
-       }
-
-       return 0;
-}
-
-/**
- * mei_irq_thread_read_handler - bottom half read routine after ISR to
- * handle the read processing.
- *
- * @cmpl_list: An instance of our list structure
- * @dev: the device structure
- * @slots: slots to read.
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list,
-               struct mei_device *dev,
-               s32 *slots)
-{
-       struct mei_msg_hdr *mei_hdr;
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
-       int ret = 0;
-
-       if (!dev->rd_msg_hdr) {
-               dev->rd_msg_hdr = mei_mecbrw_read(dev);
-               dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
-               (*slots)--;
-               dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
-       }
-       mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
-       dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length);
-
-       if (mei_hdr->reserved || !dev->rd_msg_hdr) {
-               dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
-               ret = -EBADMSG;
-               goto end;
-       }
-
-       if (mei_hdr->host_addr || mei_hdr->me_addr) {
-               list_for_each_entry_safe(cl_pos, cl_next,
-                                       &dev->file_list, link) {
-                       dev_dbg(&dev->pdev->dev,
-                                       "list_for_each_entry_safe read host"
-                                       " client = %d, ME client = %d\n",
-                                       cl_pos->host_client_id,
-                                       cl_pos->me_client_id);
-                       if (cl_pos->host_client_id == mei_hdr->host_addr &&
-                           cl_pos->me_client_id == mei_hdr->me_addr)
-                               break;
-               }
-
-               if (&cl_pos->link == &dev->file_list) {
-                       dev_dbg(&dev->pdev->dev, "corrupted message header\n");
-                       ret = -EBADMSG;
-                       goto end;
-               }
-       }
-       if (((*slots) * sizeof(u32)) < mei_hdr->length) {
-               dev_dbg(&dev->pdev->dev,
-                               "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 (!mei_hdr->host_addr) {
-               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
-               mei_irq_thread_read_bus_message(dev, mei_hdr);
-               dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
-       } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
-                  (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
-                  (dev->iamthif_state == MEI_IAMTHIF_READING)) {
-               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
-               dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
-                               mei_hdr->length);
-               ret = mei_irq_thread_read_amthi_message(cmpl_list,
-                                                       dev, mei_hdr);
-               if (ret)
-                       goto end;
-
-       } else {
-               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
-               ret = mei_irq_thread_read_client_message(cmpl_list,
-                                                        dev, mei_hdr);
-               if (ret)
-                       goto end;
-
-       }
-
-       /* reset the number of slots and header */
-       *slots = mei_count_full_read_slots(dev);
-       dev->rd_msg_hdr = 0;
-
-       if (*slots == -EOVERFLOW) {
-               /* overflow - reset */
-               dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
-               /* set the event since message has been read */
-               ret = -ERANGE;
-               goto end;
-       }
-end:
-       return ret;
-}
-
-
-/**
- * mei_irq_thread_write_handler - bottom half write routine after
- * ISR to handle the write processing.
- *
- * @cmpl_list: An instance of our list structure
- * @dev: the device structure
- * @slots: slots to write.
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
-               struct mei_device *dev,
-               s32 *slots)
-{
-
-       struct mei_cl *cl;
-       struct mei_cl_cb *pos = NULL, *next = NULL;
-       struct mei_io_list *list;
-       int ret;
-
-       if (!mei_host_buffer_is_empty(dev)) {
-               dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
-               return 0;
-       }
-       *slots = mei_count_empty_write_slots(dev);
-       /* complete all waiting for write CB */
-       dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
-
-       list = &dev->write_waiting_list;
-       list_for_each_entry_safe(pos, next,
-                       &list->mei_cb.cb_list, cb_list) {
-               cl = (struct mei_cl *)pos->file_private;
-               if (cl == NULL)
-                       continue;
-
-               cl->status = 0;
-               list_del(&pos->cb_list);
-               if (MEI_WRITING == cl->writing_state &&
-                  (pos->major_file_operations == MEI_WRITE) &&
-                  (cl != &dev->iamthif_cl)) {
-                       dev_dbg(&dev->pdev->dev,
-                               "MEI WRITE COMPLETE\n");
-                       cl->writing_state = MEI_WRITE_COMPLETE;
-                       list_add_tail(&pos->cb_list,
-                               &cmpl_list->mei_cb.cb_list);
-               }
-               if (cl == &dev->iamthif_cl) {
-                       dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
-                       if (dev->iamthif_flow_control_pending) {
-                               ret = _mei_irq_thread_iamthif_read(
-                                               dev, slots);
-                               if (ret)
-                                       return ret;
-                       }
-               }
-       }
-
-       if (dev->stop && !dev->wd_pending) {
-               dev->wd_stopped = true;
-               wake_up_interruptible(&dev->wait_stop_wd);
-               return 0;
-       }
-
-       if (dev->extra_write_index) {
-               dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n",
-                               dev->extra_write_index);
-               mei_write_message(dev,
-                               (struct mei_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->mei_state == MEI_ENABLED) {
-               if (dev->wd_pending &&
-                       mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
-                       if (mei_wd_send(dev))
-                               dev_dbg(&dev->pdev->dev, "wd send failed.\n");
-                       else
-                               if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
-                                       return -ENODEV;
-
-                       dev->wd_pending = false;
-
-                       if (dev->wd_timeout) {
-                               *slots -= (sizeof(struct mei_msg_hdr) +
-                                        MEI_START_WD_DATA_SIZE + 3) / 4;
-                               dev->wd_due_counter = 2;
-                       } else {
-                               *slots -= (sizeof(struct mei_msg_hdr) +
-                                        MEI_WD_PARAMS_SIZE + 3) / 4;
-                               dev->wd_due_counter = 0;
-                       }
-
-               }
-       }
-       if (dev->stop)
-               return -ENODEV;
-
-       /* complete control write list CB */
-       dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
-       list_for_each_entry_safe(pos, next,
-                               &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) {
-               cl = (struct mei_cl *) pos->file_private;
-               if (!cl) {
-                       list_del(&pos->cb_list);
-                       return -ENODEV;
-               }
-               switch (pos->major_file_operations) {
-               case MEI_CLOSE:
-                       /* send disconnect message */
-                       ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list);
-                       if (ret)
-                               return ret;
-
-                       break;
-               case MEI_READ:
-                       /* send flow control message */
-                       ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list);
-                       if (ret)
-                               return ret;
-
-                       break;
-               case MEI_IOCTL:
-                       /* connect message */
-                       if (mei_other_client_is_connecting(dev, cl))
-                               continue;
-                       ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list);
-                       if (ret)
-                               return ret;
-
-                       break;
-
-               default:
-                       BUG();
-               }
-
-       }
-       /* complete  write list CB */
-       dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
-       list_for_each_entry_safe(pos, next,
-                       &dev->write_list.mei_cb.cb_list, cb_list) {
-               cl = (struct mei_cl *)pos->file_private;
-               if (cl == NULL)
-                       continue;
-
-               if (cl != &dev->iamthif_cl) {
-                       if (!mei_flow_ctrl_creds(dev, cl)) {
-                               dev_dbg(&dev->pdev->dev,
-                                       "No flow control"
-                                   " credentials for client"
-                                   " %d, not sending.\n",
-                                   cl->host_client_id);
-                               continue;
-                       }
-                       ret = _mei_irq_thread_cmpl(dev, slots,
-                                           pos,
-                                           cl, cmpl_list);
-                       if (ret)
-                               return ret;
-
-               } else if (cl == &dev->iamthif_cl) {
-                       /* IAMTHIF IOCTL */
-                       dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n");
-                       if (!mei_flow_ctrl_creds(dev, cl)) {
-                               dev_dbg(&dev->pdev->dev,
-                                       "No flow control"
-                                   " credentials for amthi"
-                                   " client %d.\n",
-                                   cl->host_client_id);
-                               continue;
-                       }
-                       ret = _mei_irq_thread_cmpl_iamthif(dev,
-                                               slots,
-                                               pos,
-                                               cl,
-                                               cmpl_list);
-                       if (ret)
-                               return ret;
-
-               }
-
-       }
-       return 0;
-}
-
-
-
-/**
- * mei_timer - timer function.
- *
- * @work: pointer to the work_struct structure
- *
- * NOTE: This function is called by timer interrupt work
- */
-void mei_timer(struct work_struct *work)
-{
-       unsigned long timeout;
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
-       struct list_head *amthi_complete_list = NULL;
-       struct mei_cl_cb  *cb_pos = NULL;
-       struct mei_cl_cb  *cb_next = NULL;
-
-       struct mei_device *dev = container_of(work,
-                                       struct mei_device, timer_work.work);
-
-
-       mutex_lock(&dev->device_lock);
-       if (dev->mei_state != MEI_ENABLED) {
-               if (dev->mei_state == MEI_INIT_CLIENTS) {
-                       if (dev->init_clients_timer) {
-                               if (--dev->init_clients_timer == 0) {
-                                       dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
-                                               dev->init_clients_state);
-                                       mei_reset(dev, 1);
-                               }
-                       }
-               }
-               goto out;
-       }
-       /*** connect/disconnect timeouts ***/
-       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-               if (cl_pos->timer_count) {
-                       if (--cl_pos->timer_count == 0) {
-                               dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
-                               mei_reset(dev, 1);
-                               goto out;
-                       }
-               }
-       }
-
-       if (dev->iamthif_stall_timer) {
-               if (--dev->iamthif_stall_timer == 0) {
-                       dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
-                       mei_reset(dev, 1);
-                       dev->iamthif_msg_buf_size = 0;
-                       dev->iamthif_msg_buf_index = 0;
-                       dev->iamthif_canceled = false;
-                       dev->iamthif_ioctl = true;
-                       dev->iamthif_state = MEI_IAMTHIF_IDLE;
-                       dev->iamthif_timer = 0;
-
-                       if (dev->iamthif_current_cb)
-                               mei_free_cb_private(dev->iamthif_current_cb);
-
-                       dev->iamthif_file_object = NULL;
-                       dev->iamthif_current_cb = NULL;
-                       mei_run_next_iamthif_cmd(dev);
-               }
-       }
-
-       if (dev->iamthif_timer) {
-
-               timeout = dev->iamthif_timer +
-                               msecs_to_jiffies(IAMTHIF_READ_TIMER);
-
-               dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
-                               dev->iamthif_timer);
-               dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
-               dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
-               if (time_after(jiffies, timeout)) {
-                       /*
-                        * User didn't read the AMTHI data on time (15sec)
-                        * freeing AMTHI for other requests
-                        */
-
-                       dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
-
-                       amthi_complete_list = &dev->amthi_read_complete_list.
-                                       mei_cb.cb_list;
-
-                       list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) {
-
-                               cl_pos = cb_pos->file_object->private_data;
-
-                               /* Finding the AMTHI entry. */
-                               if (cl_pos == &dev->iamthif_cl)
-                                       list_del(&cb_pos->cb_list);
-                       }
-                       if (dev->iamthif_current_cb)
-                               mei_free_cb_private(dev->iamthif_current_cb);
-
-                       dev->iamthif_file_object->private_data = NULL;
-                       dev->iamthif_file_object = NULL;
-                       dev->iamthif_current_cb = NULL;
-                       dev->iamthif_timer = 0;
-                       mei_run_next_iamthif_cmd(dev);
-
-               }
-       }
-out:
-       schedule_delayed_work(&dev->timer_work, 2 * HZ);
-       mutex_unlock(&dev->device_lock);
-}
-
-/**
- *  mei_interrupt_thread_handler - function called after ISR to handle the interrupt
- * processing.
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- *
- */
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
-{
-       struct mei_device *dev = (struct mei_device *) dev_id;
-       struct mei_io_list complete_list;
-       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-       struct mei_cl *cl;
-       s32 slots;
-       int rets;
-       bool  bus_message_received;
-
-
-       dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
-       /* initialize our complete list */
-       mutex_lock(&dev->device_lock);
-       mei_io_list_init(&complete_list);
-       dev->host_hw_state = mei_hcsr_read(dev);
-
-       /* Ack the interrupt here
-        * In case of MSI we don't go through the quick handler */
-       if (pci_dev_msi_enabled(dev->pdev))
-               mei_reg_write(dev, H_CSR, dev->host_hw_state);
-
-       dev->me_hw_state = mei_mecsr_read(dev);
-
-       /* check if ME wants a reset */
-       if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
-           dev->mei_state != MEI_RESETING &&
-           dev->mei_state != MEI_INITIALIZING) {
-               dev_dbg(&dev->pdev->dev, "FW not ready.\n");
-               mei_reset(dev, 1);
-               mutex_unlock(&dev->device_lock);
-               return IRQ_HANDLED;
-       }
-
-       /*  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) {
-                       dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
-                       dev->host_hw_state |= (H_IE | H_IG | H_RDY);
-                       mei_hcsr_set(dev);
-                       dev->mei_state = MEI_INIT_CLIENTS;
-                       dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
-                       /* link is established
-                        * start sending messages.
-                        */
-                       mei_host_start_message(dev);
-                       mutex_unlock(&dev->device_lock);
-                       return IRQ_HANDLED;
-               } else {
-                       dev_dbg(&dev->pdev->dev, "FW not ready.\n");
-                       mutex_unlock(&dev->device_lock);
-                       return IRQ_HANDLED;
-               }
-       }
-       /* check slots available for reading */
-       slots = mei_count_full_read_slots(dev);
-       dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
-               slots, dev->extra_write_index);
-       while (slots > 0 && !dev->extra_write_index) {
-               dev_dbg(&dev->pdev->dev, "slots =%08x  extra_write_index =%08x.\n",
-                               slots, dev->extra_write_index);
-               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
-               rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
-               if (rets)
-                       goto end;
-       }
-       rets = mei_irq_thread_write_handler(&complete_list, dev, &slots);
-end:
-       dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
-       dev->host_hw_state = mei_hcsr_read(dev);
-       dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
-
-       bus_message_received = false;
-       if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
-               dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
-               bus_message_received = true;
-       }
-       mutex_unlock(&dev->device_lock);
-       if (bus_message_received) {
-               dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
-               wake_up_interruptible(&dev->wait_recvd_msg);
-               bus_message_received = false;
-       }
-       if (list_empty(&complete_list.mei_cb.cb_list))
-               return IRQ_HANDLED;
-
-
-       list_for_each_entry_safe(cb_pos, cb_next,
-                       &complete_list.mei_cb.cb_list, cb_list) {
-               cl = (struct mei_cl *)cb_pos->file_private;
-               list_del(&cb_pos->cb_list);
-               if (cl) {
-                       if (cl != &dev->iamthif_cl) {
-                               dev_dbg(&dev->pdev->dev, "completing call back.\n");
-                               _mei_cmpl(cl, cb_pos);
-                               cb_pos = NULL;
-                       } else if (cl == &dev->iamthif_cl) {
-                               _mei_cmpl_iamthif(dev, cb_pos);
-                       }
-               }
-       }
-       return IRQ_HANDLED;
-}
diff --git a/drivers/staging/mei/iorw.c b/drivers/staging/mei/iorw.c
deleted file mode 100644 (file)
index 0a80dc4..0000000
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-
-#include <linux/kernel.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/init.h>
-#include <linux/ioctl.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/uuid.h>
-#include <linux/jiffies.h>
-#include <linux/uaccess.h>
-
-
-#include "mei_dev.h"
-#include "hw.h"
-#include "mei.h"
-#include "interface.h"
-
-
-
-/**
- * mei_ioctl_connect_client - the connect to fw client IOCTL function
- *
- * @dev: the device structure
- * @data: IOCTL connect data, input and output parameters
- * @file: private data of the file object
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_ioctl_connect_client(struct file *file,
-                       struct mei_connect_client_data *data)
-{
-       struct mei_device *dev;
-       struct mei_cl_cb *cb;
-       struct mei_client *client;
-       struct mei_cl *cl;
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
-       long timeout = CONNECT_TIMEOUT;
-       int i;
-       int err;
-       int rets;
-
-       cl = file->private_data;
-       if (WARN_ON(!cl || !cl->dev))
-               return -ENODEV;
-
-       dev = cl->dev;
-
-       dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
-
-
-       /* buffered ioctl cb */
-       cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
-       if (!cb) {
-               rets = -ENOMEM;
-               goto end;
-       }
-       INIT_LIST_HEAD(&cb->cb_list);
-
-       cb->major_file_operations = MEI_IOCTL;
-
-       if (dev->mei_state != MEI_ENABLED) {
-               rets = -ENODEV;
-               goto end;
-       }
-       if (cl->state != MEI_FILE_INITIALIZING &&
-           cl->state != MEI_FILE_DISCONNECTED) {
-               rets = -EBUSY;
-               goto end;
-       }
-
-       /* find ME client we're trying to connect to */
-       i = mei_find_me_client_index(dev, data->in_client_uuid);
-       if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
-               cl->me_client_id = dev->me_clients[i].client_id;
-               cl->state = MEI_FILE_CONNECTING;
-       }
-
-       dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
-                       cl->me_client_id);
-       dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
-                       dev->me_clients[i].props.protocol_version);
-       dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
-                       dev->me_clients[i].props.max_msg_length);
-
-       /* if we're connecting to amthi client then we will use the
-        * existing connection
-        */
-       if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
-               dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
-               if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
-                       rets = -ENODEV;
-                       goto end;
-               }
-               clear_bit(cl->host_client_id, dev->host_clients_map);
-               list_for_each_entry_safe(cl_pos, cl_next,
-                                        &dev->file_list, link) {
-                       if (mei_cl_cmp_id(cl, cl_pos)) {
-                               dev_dbg(&dev->pdev->dev,
-                                       "remove file private data node host"
-                                   " client = %d, ME client = %d.\n",
-                                   cl_pos->host_client_id,
-                                   cl_pos->me_client_id);
-                               list_del(&cl_pos->link);
-                       }
-
-               }
-               dev_dbg(&dev->pdev->dev, "free file private data memory.\n");
-               kfree(cl);
-
-               cl = NULL;
-               file->private_data = &dev->iamthif_cl;
-
-               client = &data->out_client_properties;
-               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_cl.status;
-
-               goto end;
-       }
-
-       if (cl->state != MEI_FILE_CONNECTING) {
-               rets = -ENODEV;
-               goto end;
-       }
-
-
-       /* prepare the output buffer */
-       client = &data->out_client_properties;
-       client->max_msg_length = dev->me_clients[i].props.max_msg_length;
-       client->protocol_version = dev->me_clients[i].props.protocol_version;
-       dev_dbg(&dev->pdev->dev, "Can connect?\n");
-       if (dev->mei_host_buffer_is_empty
-           && !mei_other_client_is_connecting(dev, cl)) {
-               dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
-               dev->mei_host_buffer_is_empty = false;
-               if (mei_connect(dev, cl)) {
-                       dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
-                       rets = -ENODEV;
-                       goto end;
-               } else {
-                       dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
-                       cl->timer_count = MEI_CONNECT_TIMEOUT;
-                       cb->file_private = cl;
-                       list_add_tail(&cb->cb_list,
-                                     &dev->ctrl_rd_list.mei_cb.
-                                     cb_list);
-               }
-
-
-       } else {
-               dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
-               cb->file_private = cl;
-               dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
-               list_add_tail(&cb->cb_list,
-                             &dev->ctrl_wr_list.mei_cb.cb_list);
-       }
-       mutex_unlock(&dev->device_lock);
-       err = wait_event_timeout(dev->wait_recvd_msg,
-                       (MEI_FILE_CONNECTED == cl->state ||
-                        MEI_FILE_DISCONNECTED == cl->state),
-                       timeout * HZ);
-
-       mutex_lock(&dev->device_lock);
-       if (MEI_FILE_CONNECTED == cl->state) {
-               dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
-               rets = cl->status;
-               goto end;
-       } else {
-               dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
-                   cl->state);
-               if (!err) {
-                       dev_dbg(&dev->pdev->dev,
-                               "wait_event_interruptible_timeout failed on client"
-                               " connect message fw response message.\n");
-               }
-               rets = -EFAULT;
-
-               mei_io_list_flush(&dev->ctrl_rd_list, cl);
-               mei_io_list_flush(&dev->ctrl_wr_list, cl);
-               goto end;
-       }
-       rets = 0;
-end:
-       dev_dbg(&dev->pdev->dev, "free connect cb memory.");
-       kfree(cb);
-       return rets;
-}
-
-/**
- * find_amthi_read_list_entry - finds a amthilist entry for current file
- *
- * @dev: the device structure
- * @file: pointer to file object
- *
- * returns   returned a list entry on success, NULL on failure.
- */
-struct mei_cl_cb *find_amthi_read_list_entry(
-               struct mei_device *dev,
-               struct file *file)
-{
-       struct mei_cl *cl_temp;
-       struct mei_cl_cb *pos = NULL;
-       struct mei_cl_cb *next = NULL;
-
-       list_for_each_entry_safe(pos, next,
-           &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) {
-               cl_temp = (struct mei_cl *)pos->file_private;
-               if (cl_temp && cl_temp == &dev->iamthif_cl &&
-                       pos->file_object == file)
-                       return pos;
-       }
-       return NULL;
-}
-
-/**
- * amthi_read - read data from AMTHI client
- *
- * @dev: the device structure
- * @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
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns
- *  returned data length on success,
- *  zero if no data to read,
- *  negative on failure.
- */
-int amthi_read(struct mei_device *dev, struct file *file,
-              char __user *ubuf, size_t length, loff_t *offset)
-{
-       int rets;
-       int wait_ret;
-       struct mei_cl_cb *cb = NULL;
-       struct mei_cl *cl = file->private_data;
-       unsigned long timeout;
-       int i;
-
-       /* Only Posible if we are in timeout */
-       if (!cl || cl != &dev->iamthif_cl) {
-               dev_dbg(&dev->pdev->dev, "bad file ext.\n");
-               return -ETIMEDOUT;
-       }
-
-       for (i = 0; i < dev->me_clients_num; i++) {
-               if (dev->me_clients[i].client_id ==
-                   dev->iamthif_cl.me_client_id)
-                       break;
-       }
-
-       if (i == dev->me_clients_num) {
-               dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
-               return -ENODEV;
-       }
-       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id))
-               return -ENODEV;
-
-       dev_dbg(&dev->pdev->dev, "checking amthi data\n");
-       cb = find_amthi_read_list_entry(dev, file);
-
-       /* Check for if we can block or not*/
-       if (cb == NULL && file->f_flags & O_NONBLOCK)
-               return -EAGAIN;
-
-
-       dev_dbg(&dev->pdev->dev, "waiting for amthi data\n");
-       while (cb == NULL) {
-               /* unlock the Mutex */
-               mutex_unlock(&dev->device_lock);
-
-               wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
-                       (cb = find_amthi_read_list_entry(dev, file)));
-
-               if (wait_ret)
-                       return -ERESTARTSYS;
-
-               dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
-
-               /* Locking again the Mutex */
-               mutex_lock(&dev->device_lock);
-       }
-
-
-       dev_dbg(&dev->pdev->dev, "Got amthi data\n");
-       dev->iamthif_timer = 0;
-
-       if (cb) {
-               timeout = cb->read_time +
-                                       msecs_to_jiffies(IAMTHIF_READ_TIMER);
-               dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
-                               timeout);
-
-               if  (time_after(jiffies, timeout)) {
-                       dev_dbg(&dev->pdev->dev, "amthi Time out\n");
-                       /* 15 sec for the message has expired */
-                       list_del(&cb->cb_list);
-                       rets = -ETIMEDOUT;
-                       goto free;
-               }
-       }
-       /* if the whole message will fit remove it from the list */
-       if (cb->information >= *offset && length >= (cb->information - *offset))
-               list_del(&cb->cb_list);
-       else if (cb->information > 0 && cb->information <= *offset) {
-               /* end of the message has been reached */
-               list_del(&cb->cb_list);
-               rets = 0;
-               goto free;
-       }
-               /* else means that not full buffer will be read and do not
-                * remove message from deletion list
-                */
-
-       dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n",
-           cb->response_buffer.size);
-       dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n",
-           cb->information);
-
-       /* length is being turncated to PAGE_SIZE, however,
-        * the information may be longer */
-       length = min_t(size_t, length, (cb->information - *offset));
-
-       if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
-               rets = -EFAULT;
-       else {
-               rets = length;
-               if ((*offset + length) < cb->information) {
-                       *offset += length;
-                       goto out;
-               }
-       }
-free:
-       dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n");
-       *offset = 0;
-       mei_free_cb_private(cb);
-out:
-       return rets;
-}
-
-/**
- * mei_start_read - the start read client message function.
- *
- * @dev: the device structure
- * @if_num:  minor number
- * @cl: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
-{
-       struct mei_cl_cb *cb;
-       int rets = 0;
-       int i;
-
-       if (cl->state != MEI_FILE_CONNECTED)
-               return -ENODEV;
-
-       if (dev->mei_state != MEI_ENABLED)
-               return -ENODEV;
-
-       dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
-       if (cl->read_pending || cl->read_cb) {
-               dev_dbg(&dev->pdev->dev, "read is pending.\n");
-               return -EBUSY;
-       }
-
-       cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
-       if (!cb)
-               return -ENOMEM;
-
-       dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
-               cl->host_client_id, cl->me_client_id);
-
-       for (i = 0; i < dev->me_clients_num; i++) {
-               if (dev->me_clients[i].client_id == cl->me_client_id)
-                       break;
-
-       }
-
-       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-               rets = -ENODEV;
-               goto unlock;
-       }
-
-       if (i == dev->me_clients_num) {
-               rets = -ENODEV;
-               goto unlock;
-       }
-
-       cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
-       cb->response_buffer.data =
-                       kmalloc(cb->response_buffer.size, GFP_KERNEL);
-       if (!cb->response_buffer.data) {
-               rets = -ENOMEM;
-               goto unlock;
-       }
-       dev_dbg(&dev->pdev->dev, "allocation call back data success.\n");
-       cb->major_file_operations = MEI_READ;
-       /* make sure information is zero before we start */
-       cb->information = 0;
-       cb->file_private = (void *) cl;
-       cl->read_cb = cb;
-       if (dev->mei_host_buffer_is_empty) {
-               dev->mei_host_buffer_is_empty = false;
-               if (mei_send_flow_control(dev, cl)) {
-                       rets = -ENODEV;
-                       goto unlock;
-               }
-               list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list);
-       } else {
-               list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list);
-       }
-       return rets;
-unlock:
-       mei_free_cb_private(cb);
-       return rets;
-}
-
-/**
- * amthi_write - write iamthif data to amthi client
- *
- * @dev: the device structure
- * @cb: mei call back struct
- *
- * returns 0 on success, <0 on failure.
- */
-int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
-{
-       struct mei_msg_hdr mei_hdr;
-       int ret;
-
-       if (!dev || !cb)
-               return -ENODEV;
-
-       dev_dbg(&dev->pdev->dev, "write data to amthi client.\n");
-
-       dev->iamthif_state = MEI_IAMTHIF_WRITING;
-       dev->iamthif_current_cb = cb;
-       dev->iamthif_file_object = cb->file_object;
-       dev->iamthif_canceled = false;
-       dev->iamthif_ioctl = true;
-       dev->iamthif_msg_buf_size = cb->request_buffer.size;
-       memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
-              cb->request_buffer.size);
-
-       ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl);
-       if (ret < 0)
-               return ret;
-
-       if (ret && dev->mei_host_buffer_is_empty) {
-               ret = 0;
-               dev->mei_host_buffer_is_empty = false;
-               if (cb->request_buffer.size >
-                       (((dev->host_hw_state & H_CBD) >> 24) * sizeof(u32))
-                               -sizeof(struct mei_msg_hdr)) {
-                       mei_hdr.length =
-                           (((dev->host_hw_state & H_CBD) >> 24) *
-                           sizeof(u32)) - sizeof(struct mei_msg_hdr);
-                       mei_hdr.msg_complete = 0;
-               } else {
-                       mei_hdr.length = cb->request_buffer.size;
-                       mei_hdr.msg_complete = 1;
-               }
-
-               mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
-               mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
-               mei_hdr.reserved = 0;
-               dev->iamthif_msg_buf_index += mei_hdr.length;
-               if (mei_write_message(dev, &mei_hdr,
-                                       (unsigned char *)(dev->iamthif_msg_buf),
-                                       mei_hdr.length))
-                       return -ENODEV;
-
-               if (mei_hdr.msg_complete) {
-                       if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
-                               return -ENODEV;
-                       dev->iamthif_flow_control_pending = true;
-                       dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
-                       dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
-                       dev->iamthif_current_cb = cb;
-                       dev->iamthif_file_object = cb->file_object;
-                       list_add_tail(&cb->cb_list,
-                                     &dev->write_waiting_list.mei_cb.cb_list);
-               } else {
-                       dev_dbg(&dev->pdev->dev, "message does not complete, "
-                                       "so add amthi cb to write list.\n");
-                       list_add_tail(&cb->cb_list,
-                                     &dev->write_list.mei_cb.cb_list);
-               }
-       } else {
-               if (!(dev->mei_host_buffer_is_empty))
-                       dev_dbg(&dev->pdev->dev, "host buffer is not empty");
-
-               dev_dbg(&dev->pdev->dev, "No flow control credentials, "
-                               "so add iamthif cb to write list.\n");
-               list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list);
-       }
-       return 0;
-}
-
-/**
- * iamthif_ioctl_send_msg - send cmd data to amthi client
- *
- * @dev: the device structure
- *
- * returns 0 on success, <0 on failure.
- */
-void mei_run_next_iamthif_cmd(struct mei_device *dev)
-{
-       struct mei_cl *cl_tmp;
-       struct mei_cl_cb *pos = NULL;
-       struct mei_cl_cb *next = NULL;
-       int status;
-
-       if (!dev)
-               return;
-
-       dev->iamthif_msg_buf_size = 0;
-       dev->iamthif_msg_buf_index = 0;
-       dev->iamthif_canceled = false;
-       dev->iamthif_ioctl = true;
-       dev->iamthif_state = MEI_IAMTHIF_IDLE;
-       dev->iamthif_timer = 0;
-       dev->iamthif_file_object = NULL;
-
-       dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n");
-
-       list_for_each_entry_safe(pos, next,
-                       &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) {
-               list_del(&pos->cb_list);
-               cl_tmp = (struct mei_cl *)pos->file_private;
-
-               if (cl_tmp && cl_tmp == &dev->iamthif_cl) {
-                       status = amthi_write(dev, pos);
-                       if (status) {
-                               dev_dbg(&dev->pdev->dev,
-                                       "amthi write failed status = %d\n",
-                                               status);
-                               return;
-                       }
-                       break;
-               }
-       }
-}
-
-/**
- * mei_free_cb_private - free mei_cb_private related memory
- *
- * @cb: mei callback struct
- */
-void mei_free_cb_private(struct mei_cl_cb *cb)
-{
-       if (cb == NULL)
-               return;
-
-       kfree(cb->request_buffer.data);
-       kfree(cb->response_buffer.data);
-       kfree(cb);
-}
diff --git a/drivers/staging/mei/main.c b/drivers/staging/mei/main.c
deleted file mode 100644 (file)
index 20f80df..0000000
+++ /dev/null
@@ -1,1230 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/device.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/poll.h>
-#include <linux/init.h>
-#include <linux/ioctl.h>
-#include <linux/cdev.h>
-#include <linux/sched.h>
-#include <linux/uuid.h>
-#include <linux/compat.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/miscdevice.h>
-
-#include "mei_dev.h"
-#include "mei.h"
-#include "interface.h"
-
-static const char mei_driver_name[] = "mei";
-
-/* The device pointer */
-/* Currently this driver works as long as there is only a single AMT device. */
-struct pci_dev *mei_device;
-
-/* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
-
-       /* required last entry */
-       {0, }
-};
-
-MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
-
-static DEFINE_MUTEX(mei_mutex);
-
-
-/**
- * mei_clear_list - removes all callbacks associated with file
- *             from mei_cb_list
- *
- * @dev: device structure.
- * @file: file structure
- * @mei_cb_list: callbacks list
- *
- * mei_clear_list is called to clear resources associated with file
- * when application calls close function or Ctrl-C was pressed
- *
- * returns true if callback removed from the list, false otherwise
- */
-static bool mei_clear_list(struct mei_device *dev,
-               struct file *file, struct list_head *mei_cb_list)
-{
-       struct mei_cl_cb *cb_pos = NULL;
-       struct mei_cl_cb *cb_next = NULL;
-       struct file *file_temp;
-       bool removed = false;
-
-       /* list all list member */
-       list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) {
-               file_temp = (struct file *)cb_pos->file_object;
-               /* check if list member associated with a file */
-               if (file_temp == file) {
-                       /* remove member from the list */
-                       list_del(&cb_pos->cb_list);
-                       /* check if cb equal to current iamthif cb */
-                       if (dev->iamthif_current_cb == cb_pos) {
-                               dev->iamthif_current_cb = NULL;
-                               /* send flow control to iamthif client */
-                               mei_send_flow_control(dev, &dev->iamthif_cl);
-                       }
-                       /* free all allocated buffers */
-                       mei_free_cb_private(cb_pos);
-                       cb_pos = NULL;
-                       removed = true;
-               }
-       }
-       return removed;
-}
-
-/**
- * mei_clear_lists - removes all callbacks associated with file
- *
- * @dev: device structure
- * @file: file structure
- *
- * mei_clear_lists is called to clear resources associated with file
- * when application calls close function or Ctrl-C was pressed
- *
- * returns true if callback removed from the list, false otherwise
- */
-static bool mei_clear_lists(struct mei_device *dev, struct file *file)
-{
-       bool removed = false;
-
-       /* remove callbacks associated with a file */
-       mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list);
-       if (mei_clear_list(dev, file,
-                           &dev->amthi_read_complete_list.mei_cb.cb_list))
-               removed = true;
-
-       mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list);
-
-       if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list))
-               removed = true;
-
-       if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list))
-               removed = true;
-
-       if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list))
-               removed = true;
-
-       /* check if iamthif_current_cb not NULL */
-       if (dev->iamthif_current_cb && !removed) {
-               /* check file and iamthif current cb association */
-               if (dev->iamthif_current_cb->file_object == file) {
-                       /* remove cb */
-                       mei_free_cb_private(dev->iamthif_current_cb);
-                       dev->iamthif_current_cb = NULL;
-                       removed = true;
-               }
-       }
-       return removed;
-}
-/**
- * find_read_list_entry - find read list entry
- *
- * @dev: device structure
- * @file: pointer to file structure
- *
- * returns cb on success, NULL on error
- */
-static struct mei_cl_cb *find_read_list_entry(
-               struct mei_device *dev,
-               struct mei_cl *cl)
-{
-       struct mei_cl_cb *pos = NULL;
-       struct mei_cl_cb *next = NULL;
-
-       dev_dbg(&dev->pdev->dev, "remove read_list CB\n");
-       list_for_each_entry_safe(pos, next,
-                       &dev->read_list.mei_cb.cb_list, cb_list) {
-               struct mei_cl *cl_temp;
-               cl_temp = (struct mei_cl *)pos->file_private;
-
-               if (mei_cl_cmp_id(cl, cl_temp))
-                       return pos;
-       }
-       return NULL;
-}
-
-/**
- * mei_open - the open function
- *
- * @inode: pointer to inode structure
- * @file: pointer to file structure
- *
- * returns 0 on success, <0 on error
- */
-static int mei_open(struct inode *inode, struct file *file)
-{
-       struct mei_cl *cl;
-       struct mei_device *dev;
-       unsigned long cl_id;
-       int err;
-
-       err = -ENODEV;
-       if (!mei_device)
-               goto out;
-
-       dev = pci_get_drvdata(mei_device);
-       if (!dev)
-               goto out;
-
-       mutex_lock(&dev->device_lock);
-       err = -ENOMEM;
-       cl = mei_cl_allocate(dev);
-       if (!cl)
-               goto out_unlock;
-
-       err = -ENODEV;
-       if (dev->mei_state != MEI_ENABLED) {
-               dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED  mei_state= %d\n",
-                   dev->mei_state);
-               goto out_unlock;
-       }
-       err = -EMFILE;
-       if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT)
-               goto out_unlock;
-
-       cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
-       if (cl_id >= MEI_CLIENTS_MAX)
-               goto out_unlock;
-
-       cl->host_client_id  = cl_id;
-
-       dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id);
-
-       dev->open_handle_count++;
-
-       list_add_tail(&cl->link, &dev->file_list);
-
-       set_bit(cl->host_client_id, dev->host_clients_map);
-       cl->state = MEI_FILE_INITIALIZING;
-       cl->sm_state = 0;
-
-       file->private_data = cl;
-       mutex_unlock(&dev->device_lock);
-
-       return nonseekable_open(inode, file);
-
-out_unlock:
-       mutex_unlock(&dev->device_lock);
-       kfree(cl);
-out:
-       return err;
-}
-
-/**
- * mei_release - the release function
- *
- * @inode: pointer to inode structure
- * @file: pointer to file structure
- *
- * returns 0 on success, <0 on error
- */
-static int mei_release(struct inode *inode, struct file *file)
-{
-       struct mei_cl *cl = file->private_data;
-       struct mei_cl_cb *cb;
-       struct mei_device *dev;
-       int rets = 0;
-
-       if (WARN_ON(!cl || !cl->dev))
-               return -ENODEV;
-
-       dev = cl->dev;
-
-       mutex_lock(&dev->device_lock);
-       if (cl != &dev->iamthif_cl) {
-               if (cl->state == MEI_FILE_CONNECTED) {
-                       cl->state = MEI_FILE_DISCONNECTING;
-                       dev_dbg(&dev->pdev->dev,
-                               "disconnecting client host client = %d, "
-                           "ME client = %d\n",
-                           cl->host_client_id,
-                           cl->me_client_id);
-                       rets = mei_disconnect_host_client(dev, cl);
-               }
-               mei_cl_flush_queues(cl);
-               dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
-                   cl->host_client_id,
-                   cl->me_client_id);
-
-               if (dev->open_handle_count > 0) {
-                       clear_bit(cl->host_client_id, dev->host_clients_map);
-                       dev->open_handle_count--;
-               }
-               mei_remove_client_from_file_list(dev, cl->host_client_id);
-
-               /* free read cb */
-               cb = NULL;
-               if (cl->read_cb) {
-                       cb = find_read_list_entry(dev, cl);
-                       /* Remove entry from read list */
-                       if (cb)
-                               list_del(&cb->cb_list);
-
-                       cb = cl->read_cb;
-                       cl->read_cb = NULL;
-               }
-
-               file->private_data = NULL;
-
-               if (cb) {
-                       mei_free_cb_private(cb);
-                       cb = NULL;
-               }
-
-               kfree(cl);
-       } else {
-               if (dev->open_handle_count > 0)
-                       dev->open_handle_count--;
-
-               if (dev->iamthif_file_object == file &&
-                   dev->iamthif_state != MEI_IAMTHIF_IDLE) {
-
-                       dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n",
-                           dev->iamthif_state);
-                       dev->iamthif_canceled = true;
-                       if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
-                               dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n");
-                               mei_run_next_iamthif_cmd(dev);
-                       }
-               }
-
-               if (mei_clear_lists(dev, file))
-                       dev->iamthif_state = MEI_IAMTHIF_IDLE;
-
-       }
-       mutex_unlock(&dev->device_lock);
-       return rets;
-}
-
-
-/**
- * mei_read - the read 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 mei_read(struct file *file, char __user *ubuf,
-                       size_t length, loff_t *offset)
-{
-       struct mei_cl *cl = file->private_data;
-       struct mei_cl_cb *cb_pos = NULL;
-       struct mei_cl_cb *cb = NULL;
-       struct mei_device *dev;
-       int i;
-       int rets;
-       int err;
-
-
-       if (WARN_ON(!cl || !cl->dev))
-               return -ENODEV;
-
-       dev = cl->dev;
-
-       mutex_lock(&dev->device_lock);
-       if (dev->mei_state != MEI_ENABLED) {
-               rets = -ENODEV;
-               goto out;
-       }
-
-       if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
-               /* Do not allow to read watchdog client */
-               i = mei_find_me_client_index(dev, mei_wd_guid);
-               if (i >= 0) {
-                       struct mei_me_client *me_client = &dev->me_clients[i];
-
-                       if (cl->me_client_id == me_client->client_id) {
-                               rets = -EBADF;
-                               goto out;
-                       }
-               }
-       } else {
-               cl->sm_state &= ~MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
-       }
-
-       if (cl == &dev->iamthif_cl) {
-               rets = amthi_read(dev, file, ubuf, length, offset);
-               goto out;
-       }
-
-       if (cl->read_cb && cl->read_cb->information > *offset) {
-               cb = cl->read_cb;
-               goto copy_buffer;
-       } else if (cl->read_cb && cl->read_cb->information > 0 &&
-                  cl->read_cb->information <= *offset) {
-               cb = cl->read_cb;
-               rets = 0;
-               goto free;
-       } else if ((!cl->read_cb || !cl->read_cb->information) &&
-                   *offset > 0) {
-               /*Offset needs to be cleaned for contiguous reads*/
-               *offset = 0;
-               rets = 0;
-               goto out;
-       }
-
-       err = mei_start_read(dev, cl);
-       if (err && err != -EBUSY) {
-               dev_dbg(&dev->pdev->dev,
-                       "mei start read failure with status = %d\n", err);
-               rets = err;
-               goto out;
-       }
-
-       if (MEI_READ_COMPLETE != cl->reading_state &&
-                       !waitqueue_active(&cl->rx_wait)) {
-               if (file->f_flags & O_NONBLOCK) {
-                       rets = -EAGAIN;
-                       goto out;
-               }
-
-               mutex_unlock(&dev->device_lock);
-
-               if (wait_event_interruptible(cl->rx_wait,
-                       (MEI_READ_COMPLETE == cl->reading_state ||
-                        MEI_FILE_INITIALIZING == cl->state ||
-                        MEI_FILE_DISCONNECTED == cl->state ||
-                        MEI_FILE_DISCONNECTING == cl->state))) {
-                       if (signal_pending(current))
-                               return -EINTR;
-                       return -ERESTARTSYS;
-               }
-
-               mutex_lock(&dev->device_lock);
-               if (MEI_FILE_INITIALIZING == cl->state ||
-                   MEI_FILE_DISCONNECTED == cl->state ||
-                   MEI_FILE_DISCONNECTING == cl->state) {
-                       rets = -EBUSY;
-                       goto out;
-               }
-       }
-
-       cb = cl->read_cb;
-
-       if (!cb) {
-               rets = -ENODEV;
-               goto out;
-       }
-       if (cl->reading_state != MEI_READ_COMPLETE) {
-               rets = 0;
-               goto out;
-       }
-       /* now copy the data to user space */
-copy_buffer:
-       dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n",
-           cb->response_buffer.size);
-       dev_dbg(&dev->pdev->dev, "cb->information - %lu\n",
-           cb->information);
-       if (length == 0 || ubuf == NULL || *offset > cb->information) {
-               rets = -EMSGSIZE;
-               goto free;
-       }
-
-       /* length is being truncated to PAGE_SIZE, however, */
-       /* information size may be longer */
-       length = min_t(size_t, length, (cb->information - *offset));
-
-       if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
-               rets = -EFAULT;
-               goto free;
-       }
-
-       rets = length;
-       *offset += length;
-       if ((unsigned long)*offset < cb->information)
-               goto out;
-
-free:
-       cb_pos = find_read_list_entry(dev, cl);
-       /* Remove entry from read list */
-       if (cb_pos)
-               list_del(&cb_pos->cb_list);
-       mei_free_cb_private(cb);
-       cl->reading_state = MEI_IDLE;
-       cl->read_cb = NULL;
-       cl->read_pending = 0;
-out:
-       dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
-       mutex_unlock(&dev->device_lock);
-       return rets;
-}
-
-/**
- * mei_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 mei_write(struct file *file, const char __user *ubuf,
-                        size_t length, loff_t *offset)
-{
-       struct mei_cl *cl = file->private_data;
-       struct mei_cl_cb *write_cb = NULL;
-       struct mei_msg_hdr mei_hdr;
-       struct mei_device *dev;
-       unsigned long timeout = 0;
-       int rets;
-       int i;
-
-       if (WARN_ON(!cl || !cl->dev))
-               return -ENODEV;
-
-       dev = cl->dev;
-
-       mutex_lock(&dev->device_lock);
-
-       if (dev->mei_state != MEI_ENABLED) {
-               mutex_unlock(&dev->device_lock);
-               return -ENODEV;
-       }
-
-       if (cl == &dev->iamthif_cl) {
-               write_cb = find_amthi_read_list_entry(dev, file);
-
-               if (write_cb) {
-                       timeout = write_cb->read_time +
-                                       msecs_to_jiffies(IAMTHIF_READ_TIMER);
-
-                       if (time_after(jiffies, timeout) ||
-                                cl->reading_state == MEI_READ_COMPLETE) {
-                                       *offset = 0;
-                                       list_del(&write_cb->cb_list);
-                                       mei_free_cb_private(write_cb);
-                                       write_cb = NULL;
-                       }
-               }
-       }
-
-       /* free entry used in read */
-       if (cl->reading_state == MEI_READ_COMPLETE) {
-               *offset = 0;
-               write_cb = find_read_list_entry(dev, cl);
-               if (write_cb) {
-                       list_del(&write_cb->cb_list);
-                       mei_free_cb_private(write_cb);
-                       write_cb = NULL;
-                       cl->reading_state = MEI_IDLE;
-                       cl->read_cb = NULL;
-                       cl->read_pending = 0;
-               }
-       } else if (cl->reading_state == MEI_IDLE && !cl->read_pending)
-               *offset = 0;
-
-
-       write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
-       if (!write_cb) {
-               mutex_unlock(&dev->device_lock);
-               return -ENOMEM;
-       }
-
-       write_cb->file_object = file;
-       write_cb->file_private = cl;
-       write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
-       rets = -ENOMEM;
-       if (!write_cb->request_buffer.data)
-               goto unlock_dev;
-
-       dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length);
-
-       rets = -EFAULT;
-       if (copy_from_user(write_cb->request_buffer.data, ubuf, length))
-               goto unlock_dev;
-
-       cl->sm_state = 0;
-       if (length == 4 &&
-           ((memcmp(mei_wd_state_independence_msg[0],
-                                write_cb->request_buffer.data, 4) == 0) ||
-            (memcmp(mei_wd_state_independence_msg[1],
-                                write_cb->request_buffer.data, 4) == 0) ||
-            (memcmp(mei_wd_state_independence_msg[2],
-                                write_cb->request_buffer.data, 4) == 0)))
-               cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
-
-       INIT_LIST_HEAD(&write_cb->cb_list);
-       if (cl == &dev->iamthif_cl) {
-               write_cb->response_buffer.data =
-                   kmalloc(dev->iamthif_mtu, GFP_KERNEL);
-               if (!write_cb->response_buffer.data) {
-                       rets = -ENOMEM;
-                       goto unlock_dev;
-               }
-               if (dev->mei_state != MEI_ENABLED) {
-                       rets = -ENODEV;
-                       goto unlock_dev;
-               }
-               for (i = 0; i < dev->me_clients_num; i++) {
-                       if (dev->me_clients[i].client_id ==
-                               dev->iamthif_cl.me_client_id)
-                               break;
-               }
-
-               if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-                       rets = -ENODEV;
-                       goto unlock_dev;
-               }
-               if (i == dev->me_clients_num ||
-                   (dev->me_clients[i].client_id !=
-                     dev->iamthif_cl.me_client_id)) {
-                       rets = -ENODEV;
-                       goto unlock_dev;
-               } else if (length > dev->me_clients[i].props.max_msg_length ||
-                          length <= 0) {
-                       rets = -EMSGSIZE;
-                       goto unlock_dev;
-               }
-
-               write_cb->response_buffer.size = dev->iamthif_mtu;
-               write_cb->major_file_operations = MEI_IOCTL;
-               write_cb->information = 0;
-               write_cb->request_buffer.size = length;
-               if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
-                       rets = -ENODEV;
-                       goto unlock_dev;
-               }
-
-               if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) ||
-                               dev->iamthif_state != MEI_IAMTHIF_IDLE) {
-                       dev_dbg(&dev->pdev->dev, "amthi_state = %d\n",
-                                       (int) dev->iamthif_state);
-                       dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n");
-                       list_add_tail(&write_cb->cb_list,
-                                       &dev->amthi_cmd_list.mei_cb.cb_list);
-                       rets = length;
-               } else {
-                       dev_dbg(&dev->pdev->dev, "call amthi write\n");
-                       rets = amthi_write(dev, write_cb);
-
-                       if (rets) {
-                               dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n",
-                                   rets);
-                               goto unlock_dev;
-                       }
-                       rets = length;
-               }
-               mutex_unlock(&dev->device_lock);
-               return rets;
-       }
-
-       write_cb->major_file_operations = MEI_WRITE;
-       /* make sure information is zero before we start */
-
-       write_cb->information = 0;
-       write_cb->request_buffer.size = length;
-
-       dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
-           cl->host_client_id, cl->me_client_id);
-       if (cl->state != MEI_FILE_CONNECTED) {
-               rets = -ENODEV;
-               dev_dbg(&dev->pdev->dev, "host client = %d,  is not connected to ME client = %d",
-                   cl->host_client_id,
-                   cl->me_client_id);
-               goto unlock_dev;
-       }
-       for (i = 0; i < dev->me_clients_num; i++) {
-               if (dev->me_clients[i].client_id ==
-                   cl->me_client_id)
-                       break;
-       }
-       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-               rets = -ENODEV;
-               goto unlock_dev;
-       }
-       if (i == dev->me_clients_num) {
-               rets = -ENODEV;
-               goto unlock_dev;
-       }
-       if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
-               rets = -EINVAL;
-               goto unlock_dev;
-       }
-       write_cb->file_private = cl;
-
-       rets = mei_flow_ctrl_creds(dev, cl);
-       if (rets < 0)
-               goto unlock_dev;
-
-       if (rets && dev->mei_host_buffer_is_empty) {
-               rets = 0;
-               dev->mei_host_buffer_is_empty = false;
-               if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
-                       sizeof(u32)) - sizeof(struct mei_msg_hdr))) {
-
-                       mei_hdr.length =
-                               (((dev->host_hw_state & H_CBD) >> 24) *
-                               sizeof(u32)) -
-                               sizeof(struct mei_msg_hdr);
-                       mei_hdr.msg_complete = 0;
-               } else {
-                       mei_hdr.length = length;
-                       mei_hdr.msg_complete = 1;
-               }
-               mei_hdr.host_addr = cl->host_client_id;
-               mei_hdr.me_addr = cl->me_client_id;
-               mei_hdr.reserved = 0;
-               dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n",
-                   *((u32 *) &mei_hdr));
-               if (mei_write_message(dev, &mei_hdr,
-                       (unsigned char *) (write_cb->request_buffer.data),
-                       mei_hdr.length)) {
-                       rets = -ENODEV;
-                       goto unlock_dev;
-               }
-               cl->writing_state = MEI_WRITING;
-               write_cb->information = mei_hdr.length;
-               if (mei_hdr.msg_complete) {
-                       if (mei_flow_ctrl_reduce(dev, cl)) {
-                               rets = -ENODEV;
-                               goto unlock_dev;
-                       }
-                       list_add_tail(&write_cb->cb_list,
-                                     &dev->write_waiting_list.mei_cb.cb_list);
-               } else {
-                       list_add_tail(&write_cb->cb_list,
-                                     &dev->write_list.mei_cb.cb_list);
-               }
-
-       } else {
-
-               write_cb->information = 0;
-               cl->writing_state = MEI_WRITING;
-               list_add_tail(&write_cb->cb_list,
-                             &dev->write_list.mei_cb.cb_list);
-       }
-       mutex_unlock(&dev->device_lock);
-       return length;
-
-unlock_dev:
-       mutex_unlock(&dev->device_lock);
-       mei_free_cb_private(write_cb);
-       return rets;
-}
-
-
-/**
- * mei_ioctl - the IOCTL function
- *
- * @file: pointer to file structure
- * @cmd: ioctl command
- * @data: pointer to mei message structure
- *
- * returns 0 on success , <0 on error
- */
-static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
-{
-       struct mei_device *dev;
-       struct mei_cl *cl = file->private_data;
-       struct mei_connect_client_data *connect_data = NULL;
-       int rets;
-
-       if (cmd != IOCTL_MEI_CONNECT_CLIENT)
-               return -EINVAL;
-
-       if (WARN_ON(!cl || !cl->dev))
-               return -ENODEV;
-
-       dev = cl->dev;
-
-       dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
-
-       mutex_lock(&dev->device_lock);
-       if (dev->mei_state != MEI_ENABLED) {
-               rets = -ENODEV;
-               goto out;
-       }
-
-       dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
-
-       connect_data = kzalloc(sizeof(struct mei_connect_client_data),
-                                                       GFP_KERNEL);
-       if (!connect_data) {
-               rets = -ENOMEM;
-               goto out;
-       }
-       dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
-       if (copy_from_user(connect_data, (char __user *)data,
-                               sizeof(struct mei_connect_client_data))) {
-               dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
-               rets = -EFAULT;
-               goto out;
-       }
-       rets = mei_ioctl_connect_client(file, connect_data);
-
-       /* if all is ok, copying the data back to user. */
-       if (rets)
-               goto out;
-
-       dev_dbg(&dev->pdev->dev, "copy connect data to user\n");
-       if (copy_to_user((char __user *)data, connect_data,
-                               sizeof(struct mei_connect_client_data))) {
-               dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
-               rets = -EFAULT;
-               goto out;
-       }
-
-out:
-       kfree(connect_data);
-       mutex_unlock(&dev->device_lock);
-       return rets;
-}
-
-/**
- * mei_compat_ioctl - the compat IOCTL function
- *
- * @file: pointer to file structure
- * @cmd: ioctl command
- * @data: pointer to mei message structure
- *
- * returns 0 on success , <0 on error
- */
-#ifdef CONFIG_COMPAT
-static long mei_compat_ioctl(struct file *file,
-                       unsigned int cmd, unsigned long data)
-{
-       return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data));
-}
-#endif
-
-
-/**
- * mei_poll - the poll function
- *
- * @file: pointer to file structure
- * @wait: pointer to poll_table structure
- *
- * returns poll mask
- */
-static unsigned int mei_poll(struct file *file, poll_table *wait)
-{
-       struct mei_cl *cl = file->private_data;
-       struct mei_device *dev;
-       unsigned int mask = 0;
-
-       if (WARN_ON(!cl || !cl->dev))
-               return mask;
-
-       dev = cl->dev;
-
-       mutex_lock(&dev->device_lock);
-
-       if (dev->mei_state != MEI_ENABLED)
-               goto out;
-
-
-       if (cl == &dev->iamthif_cl) {
-               mutex_unlock(&dev->device_lock);
-               poll_wait(file, &dev->iamthif_cl.wait, wait);
-               mutex_lock(&dev->device_lock);
-               if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
-                       dev->iamthif_file_object == file) {
-                       mask |= (POLLIN | POLLRDNORM);
-                       dev_dbg(&dev->pdev->dev, "run next amthi cb\n");
-                       mei_run_next_iamthif_cmd(dev);
-               }
-               goto out;
-       }
-
-       mutex_unlock(&dev->device_lock);
-       poll_wait(file, &cl->tx_wait, wait);
-       mutex_lock(&dev->device_lock);
-       if (MEI_WRITE_COMPLETE == cl->writing_state)
-               mask |= (POLLIN | POLLRDNORM);
-
-out:
-       mutex_unlock(&dev->device_lock);
-       return mask;
-}
-
-/*
- * file operations structure will be used for mei char device.
- */
-static const struct file_operations mei_fops = {
-       .owner = THIS_MODULE,
-       .read = mei_read,
-       .unlocked_ioctl = mei_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = mei_compat_ioctl,
-#endif
-       .open = mei_open,
-       .release = mei_release,
-       .write = mei_write,
-       .poll = mei_poll,
-       .llseek = no_llseek
-};
-
-
-/*
- * Misc Device Struct
- */
-static struct miscdevice  mei_misc_device = {
-               .name = "mei",
-               .fops = &mei_fops,
-               .minor = MISC_DYNAMIC_MINOR,
-};
-
-/**
- * mei_probe - Device Initialization Routine
- *
- * @pdev: PCI device structure
- * @ent: entry in kcs_pci_tbl
- *
- * returns 0 on success, <0 on failure.
- */
-static int __devinit mei_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
-{
-       struct mei_device *dev;
-       int err;
-
-       mutex_lock(&mei_mutex);
-       if (mei_device) {
-               err = -EEXIST;
-               goto end;
-       }
-       /* enable pci dev */
-       err = pci_enable_device(pdev);
-       if (err) {
-               printk(KERN_ERR "mei: Failed to enable pci device.\n");
-               goto end;
-       }
-       /* set PCI host mastering  */
-       pci_set_master(pdev);
-       /* pci request regions for mei driver */
-       err = pci_request_regions(pdev, mei_driver_name);
-       if (err) {
-               printk(KERN_ERR "mei: Failed to get pci regions.\n");
-               goto disable_device;
-       }
-       /* allocates and initializes the mei dev structure */
-       dev = mei_device_init(pdev);
-       if (!dev) {
-               err = -ENOMEM;
-               goto release_regions;
-       }
-       /* mapping  IO device memory */
-       dev->mem_addr = pci_iomap(pdev, 0, 0);
-       if (!dev->mem_addr) {
-               printk(KERN_ERR "mei: mapping I/O device memory failure.\n");
-               err = -ENOMEM;
-               goto free_device;
-       }
-       pci_enable_msi(pdev);
-
-        /* request and enable interrupt */
-       if (pci_dev_msi_enabled(pdev))
-               err = request_threaded_irq(pdev->irq,
-                       NULL,
-                       mei_interrupt_thread_handler,
-                       0, mei_driver_name, dev);
-       else
-               err = request_threaded_irq(pdev->irq,
-                       mei_interrupt_quick_handler,
-                       mei_interrupt_thread_handler,
-                       IRQF_SHARED, mei_driver_name, dev);
-
-       if (err) {
-               printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n",
-                      pdev->irq);
-               goto unmap_memory;
-       }
-       INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
-       if (mei_hw_init(dev)) {
-               printk(KERN_ERR "mei: Init hw failure.\n");
-               err = -ENODEV;
-               goto release_irq;
-       }
-
-       err = misc_register(&mei_misc_device);
-       if (err)
-               goto release_irq;
-
-       mei_device = pdev;
-       pci_set_drvdata(pdev, dev);
-
-
-       schedule_delayed_work(&dev->timer_work, HZ);
-
-       mutex_unlock(&mei_mutex);
-
-       pr_debug("initialization successful.\n");
-
-       return 0;
-
-release_irq:
-       /* disable interrupts */
-       dev->host_hw_state = mei_hcsr_read(dev);
-       mei_disable_interrupts(dev);
-       flush_scheduled_work();
-       free_irq(pdev->irq, dev);
-       pci_disable_msi(pdev);
-unmap_memory:
-       pci_iounmap(pdev, dev->mem_addr);
-free_device:
-       kfree(dev);
-release_regions:
-       pci_release_regions(pdev);
-disable_device:
-       pci_disable_device(pdev);
-end:
-       mutex_unlock(&mei_mutex);
-       printk(KERN_ERR "mei: Driver initialization failed.\n");
-       return err;
-}
-
-/**
- * mei_remove - Device Removal Routine
- *
- * @pdev: PCI device structure
- *
- * mei_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.
- */
-static void __devexit mei_remove(struct pci_dev *pdev)
-{
-       struct mei_device *dev;
-
-       if (mei_device != pdev)
-               return;
-
-       dev = pci_get_drvdata(pdev);
-       if (!dev)
-               return;
-
-       mutex_lock(&dev->device_lock);
-
-       mei_wd_stop(dev, false);
-
-       mei_device = NULL;
-
-       if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
-               dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
-               mei_disconnect_host_client(dev, &dev->iamthif_cl);
-       }
-       if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
-               dev->wd_cl.state = MEI_FILE_DISCONNECTING;
-               mei_disconnect_host_client(dev, &dev->wd_cl);
-       }
-
-       /* Unregistering watchdog device */
-       mei_watchdog_unregister(dev);
-
-       /* remove entry if already in list */
-       dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
-       mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id);
-       mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id);
-
-       dev->iamthif_current_cb = NULL;
-       dev->me_clients_num = 0;
-
-       mutex_unlock(&dev->device_lock);
-
-       flush_scheduled_work();
-
-       /* disable interrupts */
-       mei_disable_interrupts(dev);
-
-       free_irq(pdev->irq, dev);
-       pci_disable_msi(pdev);
-       pci_set_drvdata(pdev, NULL);
-
-       if (dev->mem_addr)
-               pci_iounmap(pdev, dev->mem_addr);
-
-       kfree(dev);
-
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-}
-#ifdef CONFIG_PM
-static int mei_pci_suspend(struct device *device)
-{
-       struct pci_dev *pdev = to_pci_dev(device);
-       struct mei_device *dev = pci_get_drvdata(pdev);
-       int err;
-
-       if (!dev)
-               return -ENODEV;
-       mutex_lock(&dev->device_lock);
-       /* Stop watchdog if exists */
-       err = mei_wd_stop(dev, true);
-       /* Set new mei state */
-       if (dev->mei_state == MEI_ENABLED ||
-           dev->mei_state == MEI_RECOVERING_FROM_RESET) {
-               dev->mei_state = MEI_POWER_DOWN;
-               mei_reset(dev, 0);
-       }
-       mutex_unlock(&dev->device_lock);
-
-       free_irq(pdev->irq, dev);
-       pci_disable_msi(pdev);
-
-       return err;
-}
-
-static int mei_pci_resume(struct device *device)
-{
-       struct pci_dev *pdev = to_pci_dev(device);
-       struct mei_device *dev;
-       int err;
-
-       dev = pci_get_drvdata(pdev);
-       if (!dev)
-               return -ENODEV;
-
-       pci_enable_msi(pdev);
-
-       /* request and enable interrupt */
-       if (pci_dev_msi_enabled(pdev))
-               err = request_threaded_irq(pdev->irq,
-                       NULL,
-                       mei_interrupt_thread_handler,
-                       0, mei_driver_name, dev);
-       else
-               err = request_threaded_irq(pdev->irq,
-                       mei_interrupt_quick_handler,
-                       mei_interrupt_thread_handler,
-                       IRQF_SHARED, mei_driver_name, dev);
-
-       if (err) {
-               printk(KERN_ERR "mei: Request_irq failure. irq = %d\n",
-                      pdev->irq);
-               return err;
-       }
-
-       mutex_lock(&dev->device_lock);
-       dev->mei_state = MEI_POWER_UP;
-       mei_reset(dev, 1);
-       mutex_unlock(&dev->device_lock);
-
-       /* Start timer if stopped in suspend */
-       schedule_delayed_work(&dev->timer_work, HZ);
-
-       return err;
-}
-static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
-#define MEI_PM_OPS     (&mei_pm_ops)
-#else
-#define MEI_PM_OPS     NULL
-#endif /* CONFIG_PM */
-/*
- *  PCI driver structure
- */
-static struct pci_driver mei_driver = {
-       .name = mei_driver_name,
-       .id_table = mei_pci_tbl,
-       .probe = mei_probe,
-       .remove = __devexit_p(mei_remove),
-       .shutdown = __devexit_p(mei_remove),
-       .driver.pm = MEI_PM_OPS,
-};
-
-/**
- * mei_init_module - Driver Registration Routine
- *
- * mei_init_module is the first routine called when the driver is
- * loaded. All it does is to register with the PCI subsystem.
- *
- * returns 0 on success, <0 on failure.
- */
-static int __init mei_init_module(void)
-{
-       int ret;
-
-       pr_debug("loading.\n");
-       /* init pci module */
-       ret = pci_register_driver(&mei_driver);
-       if (ret < 0)
-               printk(KERN_ERR "mei: Error registering driver.\n");
-
-       return ret;
-}
-
-module_init(mei_init_module);
-
-/**
- * mei_exit_module - Driver Exit Cleanup Routine
- *
- * mei_exit_module is called just before the driver is removed
- * from memory.
- */
-static void __exit mei_exit_module(void)
-{
-       misc_deregister(&mei_misc_device);
-       pci_unregister_driver(&mei_driver);
-
-       pr_debug("unloaded successfully.\n");
-}
-
-module_exit(mei_exit_module);
-
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/mei/mei-amt-version.c b/drivers/staging/mei/mei-amt-version.c
deleted file mode 100644 (file)
index ac2a507..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-/******************************************************************************
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Intel MEI Interface Header
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2012 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- *     Intel Corporation.
- *     linux-mei@linux.intel.com
- *     http://www.intel.com
- *
- * BSD LICENSE
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * 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 MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * 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 DAMAGE.
- *
- *****************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <bits/wordsize.h>
-#include "mei.h"
-
-/*****************************************************************************
- * Intel Management Engine Interface
- *****************************************************************************/
-
-#define mei_msg(_me, fmt, ARGS...) do {         \
-       if (_me->verbose)                       \
-               fprintf(stderr, fmt, ##ARGS);   \
-} while (0)
-
-#define mei_err(_me, fmt, ARGS...) do {         \
-       fprintf(stderr, "Error: " fmt, ##ARGS); \
-} while (0)
-
-struct mei {
-       uuid_le guid;
-       bool initialized;
-       bool verbose;
-       unsigned int buf_size;
-       unsigned char prot_ver;
-       int fd;
-};
-
-static void mei_deinit(struct mei *cl)
-{
-       if (cl->fd != -1)
-               close(cl->fd);
-       cl->fd = -1;
-       cl->buf_size = 0;
-       cl->prot_ver = 0;
-       cl->initialized = false;
-}
-
-static bool mei_init(struct mei *me, const uuid_le *guid,
-               unsigned char req_protocol_version, bool verbose)
-{
-       int result;
-       struct mei_client *cl;
-       struct mei_connect_client_data data;
-
-       mei_deinit(me);
-
-       me->verbose = verbose;
-
-       me->fd = open("/dev/mei", O_RDWR);
-       if (me->fd == -1) {
-               mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
-               goto err;
-       }
-       memcpy(&me->guid, guid, sizeof(*guid));
-       memset(&data, 0, sizeof(data));
-       me->initialized = true;
-
-       memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
-       result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
-       if (result) {
-               mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
-               goto err;
-       }
-       cl = &data.out_client_properties;
-       mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
-       mei_msg(me, "protocol_version %d\n", cl->protocol_version);
-
-       if ((req_protocol_version > 0) &&
-            (cl->protocol_version != req_protocol_version)) {
-               mei_err(me, "Intel MEI protocol version not supported\n");
-               goto err;
-       }
-
-       me->buf_size = cl->max_msg_length;
-       me->prot_ver = cl->protocol_version;
-
-       return true;
-err:
-       mei_deinit(me);
-       return false;
-}
-
-static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
-                       ssize_t len, unsigned long timeout)
-{
-       ssize_t rc;
-
-       mei_msg(me, "call read length = %zd\n", len);
-
-       rc = read(me->fd, buffer, len);
-       if (rc < 0) {
-               mei_err(me, "read failed with status %zd %s\n",
-                               rc, strerror(errno));
-               mei_deinit(me);
-       } else {
-               mei_msg(me, "read succeeded with result %zd\n", rc);
-       }
-       return rc;
-}
-
-static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
-                       ssize_t len, unsigned long timeout)
-{
-       struct timeval tv;
-       ssize_t written;
-       ssize_t rc;
-       fd_set set;
-
-       tv.tv_sec = timeout / 1000;
-       tv.tv_usec = (timeout % 1000) * 1000000;
-
-       mei_msg(me, "call write length = %zd\n", len);
-
-       written = write(me->fd, buffer, len);
-       if (written < 0) {
-               rc = -errno;
-               mei_err(me, "write failed with status %zd %s\n",
-                       written, strerror(errno));
-               goto out;
-       }
-
-       FD_ZERO(&set);
-       FD_SET(me->fd, &set);
-       rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
-       if (rc > 0 && FD_ISSET(me->fd, &set)) {
-               mei_msg(me, "write success\n");
-       } else if (rc == 0) {
-               mei_err(me, "write failed on timeout with status\n");
-               goto out;
-       } else { /* rc < 0 */
-               mei_err(me, "write failed on select with status %zd\n", rc);
-               goto out;
-       }
-
-       rc = written;
-out:
-       if (rc < 0)
-               mei_deinit(me);
-
-       return rc;
-}
-
-/***************************************************************************
- * Intel Advanced Management Technolgy ME Client
- ***************************************************************************/
-
-#define AMT_MAJOR_VERSION 1
-#define AMT_MINOR_VERSION 1
-
-#define AMT_STATUS_SUCCESS                0x0
-#define AMT_STATUS_INTERNAL_ERROR         0x1
-#define AMT_STATUS_NOT_READY              0x2
-#define AMT_STATUS_INVALID_AMT_MODE       0x3
-#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
-
-#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE  0x4000
-#define AMT_STATUS_SDK_RESOURCES      0x1004
-
-
-#define AMT_BIOS_VERSION_LEN   65
-#define AMT_VERSIONS_NUMBER    50
-#define AMT_UNICODE_STRING_LEN 20
-
-struct amt_unicode_string {
-       uint16_t length;
-       char string[AMT_UNICODE_STRING_LEN];
-} __attribute__((packed));
-
-struct amt_version_type {
-       struct amt_unicode_string description;
-       struct amt_unicode_string version;
-} __attribute__((packed));
-
-struct amt_version {
-       uint8_t major;
-       uint8_t minor;
-} __attribute__((packed));
-
-struct amt_code_versions {
-       uint8_t bios[AMT_BIOS_VERSION_LEN];
-       uint32_t count;
-       struct amt_version_type versions[AMT_VERSIONS_NUMBER];
-} __attribute__((packed));
-
-/***************************************************************************
- * Intel Advanced Management Technolgy Host Interface
- ***************************************************************************/
-
-struct amt_host_if_msg_header {
-       struct amt_version version;
-       uint16_t _reserved;
-       uint32_t command;
-       uint32_t length;
-} __attribute__((packed));
-
-struct amt_host_if_resp_header {
-       struct amt_host_if_msg_header header;
-       uint32_t status;
-       unsigned char data[0];
-} __attribute__((packed));
-
-const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,  \
-                               0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
-
-#define AMT_HOST_IF_CODE_VERSIONS_REQUEST  0x0400001A
-#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
-
-const struct amt_host_if_msg_header CODE_VERSION_REQ = {
-       .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
-       ._reserved = 0,
-       .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
-       .length = 0
-};
-
-
-struct amt_host_if {
-       struct mei mei_cl;
-       unsigned long send_timeout;
-       bool initialized;
-};
-
-
-static bool amt_host_if_init(struct amt_host_if *acmd,
-                     unsigned long send_timeout, bool verbose)
-{
-       acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
-       acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
-       return acmd->initialized;
-}
-
-static void amt_host_if_deinit(struct amt_host_if *acmd)
-{
-       mei_deinit(&acmd->mei_cl);
-       acmd->initialized = false;
-}
-
-static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
-{
-       uint32_t status = AMT_STATUS_SUCCESS;
-       struct amt_code_versions *code_ver;
-       size_t code_ver_len;
-       uint32_t ver_type_cnt;
-       uint32_t len;
-       uint32_t i;
-
-       code_ver = (struct amt_code_versions *)resp->data;
-       /* length - sizeof(status) */
-       code_ver_len = resp->header.length - sizeof(uint32_t);
-       ver_type_cnt = code_ver_len -
-                       sizeof(code_ver->bios) -
-                       sizeof(code_ver->count);
-       if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
-               status = AMT_STATUS_INTERNAL_ERROR;
-               goto out;
-       }
-
-       for (i = 0; i < code_ver->count; i++) {
-               len = code_ver->versions[i].description.length;
-
-               if (len > AMT_UNICODE_STRING_LEN) {
-                       status = AMT_STATUS_INTERNAL_ERROR;
-                       goto out;
-               }
-
-               len = code_ver->versions[i].version.length;
-               if (code_ver->versions[i].version.string[len] != '\0' ||
-                   len != strlen(code_ver->versions[i].version.string)) {
-                       status = AMT_STATUS_INTERNAL_ERROR;
-                       goto out;
-               }
-       }
-out:
-       return status;
-}
-
-static uint32_t amt_verify_response_header(uint32_t command,
-                               const struct amt_host_if_msg_header *resp_hdr,
-                               uint32_t response_size)
-{
-       if (response_size < sizeof(struct amt_host_if_resp_header)) {
-               return AMT_STATUS_INTERNAL_ERROR;
-       } else if (response_size != (resp_hdr->length +
-                               sizeof(struct amt_host_if_msg_header))) {
-               return AMT_STATUS_INTERNAL_ERROR;
-       } else if (resp_hdr->command != command) {
-               return AMT_STATUS_INTERNAL_ERROR;
-       } else if (resp_hdr->_reserved != 0) {
-               return AMT_STATUS_INTERNAL_ERROR;
-       } else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
-                  resp_hdr->version.minor < AMT_MINOR_VERSION) {
-               return AMT_STATUS_INTERNAL_ERROR;
-       }
-       return AMT_STATUS_SUCCESS;
-}
-
-static uint32_t amt_host_if_call(struct amt_host_if *acmd,
-                       const unsigned char *command, ssize_t command_sz,
-                       uint8_t **read_buf, uint32_t rcmd,
-                       unsigned int expected_sz)
-{
-       uint32_t in_buf_sz;
-       uint32_t out_buf_sz;
-       ssize_t written;
-       uint32_t status;
-       struct amt_host_if_resp_header *msg_hdr;
-
-       in_buf_sz = acmd->mei_cl.buf_size;
-       *read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
-       if (*read_buf == NULL)
-               return AMT_STATUS_SDK_RESOURCES;
-       memset(*read_buf, 0, in_buf_sz);
-       msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
-
-       written = mei_send_msg(&acmd->mei_cl,
-                               command, command_sz, acmd->send_timeout);
-       if (written != command_sz)
-               return AMT_STATUS_INTERNAL_ERROR;
-
-       out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
-       if (out_buf_sz <= 0)
-               return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
-
-       status = msg_hdr->status;
-       if (status != AMT_STATUS_SUCCESS)
-               return status;
-
-       status = amt_verify_response_header(rcmd,
-                               &msg_hdr->header, out_buf_sz);
-       if (status != AMT_STATUS_SUCCESS)
-               return status;
-
-       if (expected_sz && expected_sz != out_buf_sz)
-               return AMT_STATUS_INTERNAL_ERROR;
-
-       return AMT_STATUS_SUCCESS;
-}
-
-
-static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
-                              struct amt_code_versions *versions)
-{
-       struct amt_host_if_resp_header *response = NULL;
-       uint32_t status;
-
-       status = amt_host_if_call(cmd,
-                       (const unsigned char *)&CODE_VERSION_REQ,
-                       sizeof(CODE_VERSION_REQ),
-                       (uint8_t **)&response,
-                       AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
-
-       if (status != AMT_STATUS_SUCCESS)
-               goto out;
-
-       status = amt_verify_code_versions(response);
-       if (status != AMT_STATUS_SUCCESS)
-               goto out;
-
-       memcpy(versions, response->data, sizeof(struct amt_code_versions));
-out:
-       if (response != NULL)
-               free(response);
-
-       return status;
-}
-
-/************************** end of amt_host_if_command ***********************/
-int main(int argc, char **argv)
-{
-       struct amt_code_versions ver;
-       struct amt_host_if acmd;
-       unsigned int i;
-       uint32_t status;
-       int ret;
-       bool verbose;
-
-       verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
-
-       if (!amt_host_if_init(&acmd, 5000, verbose)) {
-               ret = 1;
-               goto out;
-       }
-
-       status = amt_get_code_versions(&acmd, &ver);
-
-       amt_host_if_deinit(&acmd);
-
-       switch (status) {
-       case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
-               printf("Intel AMT: DISABLED\n");
-               ret = 0;
-               break;
-       case AMT_STATUS_SUCCESS:
-               printf("Intel AMT: ENABLED\n");
-               for (i = 0; i < ver.count; i++) {
-                       printf("%s:\t%s\n", ver.versions[i].description.string,
-                               ver.versions[i].version.string);
-               }
-               ret = 0;
-               break;
-       default:
-               printf("An error has occurred\n");
-               ret = 1;
-               break;
-       }
-
-out:
-       return ret;
-}
diff --git a/drivers/staging/mei/mei.h b/drivers/staging/mei/mei.h
deleted file mode 100644 (file)
index bc0d8b6..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/******************************************************************************
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Intel MEI Interface Header
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- *     Intel Corporation.
- *     linux-mei@linux.intel.com
- *     http://www.intel.com
- *
- * BSD LICENSE
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * 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 MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * 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 DAMAGE.
- *
- *****************************************************************************/
-
-#ifndef _LINUX_MEI_H
-#define _LINUX_MEI_H
-
-#include <linux/uuid.h>
-
-/*
- * This IOCTL is used to associate the current file descriptor with a
- * FW Client (given by UUID). This opens a communication channel
- * between a host client and a FW client. From this point every read and write
- * will communicate with the associated FW client.
- * Only in close() (file_operation release()) the communication between
- * the clients is disconnected
- *
- * The IOCTL argument is a struct with a union that contains
- * the input parameter and the output parameter for this IOCTL.
- *
- * The input parameter is UUID of the FW Client.
- * The output parameter is the properties of the FW client
- * (FW protocol version and max message size).
- *
- */
-#define IOCTL_MEI_CONNECT_CLIENT \
-       _IOWR('H' , 0x01, struct mei_connect_client_data)
-
-/*
- * Intel MEI client information struct
- */
-struct mei_client {
-       __u32 max_msg_length;
-       __u8 protocol_version;
-       __u8 reserved[3];
-};
-
-/*
- * IOCTL Connect Client Data structure
- */
-struct mei_connect_client_data {
-       union {
-               uuid_le in_client_uuid;
-               struct mei_client out_client_properties;
-       };
-};
-
-#endif /* _LINUX_MEI_H  */
diff --git a/drivers/staging/mei/mei.txt b/drivers/staging/mei/mei.txt
deleted file mode 100644 (file)
index 2785697..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-Intel(R) Management Engine Interface (Intel(R) MEI)
-=======================
-
-Introduction
-=======================
-
-The Intel Management Engine (Intel ME) is an isolated and protected computing
-resource (Co-processor) residing inside certain Intel chipsets. The Intel ME
-provides support for computer/IT management features. The feature set
-depends on the Intel chipset SKU.
-
-The Intel Management Engine Interface (Intel MEI, previously known as HECI)
-is the interface between the Host and Intel ME. This interface is exposed
-to the host as a PCI device. The Intel MEI Driver is in charge of the
-communication channel between a host application and the Intel ME feature.
-
-Each Intel ME feature (Intel ME Client) is addressed by a GUID/UUID and
-each client has its own protocol. The protocol is message-based with a
-header and payload up to 512 bytes.
-
-Prominent usage of the Intel ME Interface is to communicate with Intel(R)
-Active Management Technology (Intel AMT)implemented in firmware running on
-the Intel ME.
-
-Intel AMT provides the ability to manage a host remotely out-of-band (OOB)
-even when the operating system running on the host processor has crashed or
-is in a sleep state.
-
-Some examples of Intel AMT usage are:
-   - Monitoring hardware state and platform components
-   - Remote power off/on (useful for green computing or overnight IT
-     maintenance)
-   - OS updates
-   - Storage of useful platform information such as software assets
-   - Built-in hardware KVM
-   - Selective network isolation of Ethernet and IP protocol flows based
-     on policies set by a remote management console
-   - IDE device redirection from remote management console
-
-Intel AMT (OOB) communication is based on SOAP (deprecated
-starting with Release 6.0) over HTTP/S or WS-Management protocol over
-HTTP/S that are received from a remote management console application.
-
-For more information about Intel AMT:
-http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-
-Intel MEI Driver
-=======================
-
-The driver exposes a misc device called /dev/mei.
-
-An application maintains communication with an Intel ME feature while
-/dev/mei is open. The binding to a specific features is performed by calling
-MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID.
-The number of instances of an Intel ME feature that can be opened
-at the same time depends on the Intel ME feature, but most of the
-features allow only a single instance.
-
-The Intel AMT Host Interface (Intel AMTHI) feature supports multiple
-simultaneous user applications. Therefore, the Intel MEI driver handles
-this internally by maintaining request queues for the applications.
-
-The driver is oblivious to data that is passed between firmware feature
-and host application.
-
-Because some of the Intel ME features can change the system
-configuration, the driver by default allows only a privileged
-user to access it.
-
-A code snippet for an application communicating with
-Intel AMTHI client:
-       struct mei_connect_client_data data;
-       fd = open(MEI_DEVICE);
-
-       data.d.in_client_uuid = AMTHI_UUID;
-
-       ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &data);
-
-       printf("Ver=%d, MaxLen=%ld\n",
-                       data.d.in_client_uuid.protocol_version,
-                       data.d.in_client_uuid.max_msg_length);
-
-       [...]
-
-       write(fd, amthi_req_data, amthi_req_data_len);
-
-       [...]
-
-       read(fd, &amthi_res_data, amthi_res_data_len);
-
-       [...]
-       close(fd);
-
-IOCTL:
-======
-The Intel MEI Driver supports the following IOCTL command:
-       IOCTL_MEI_CONNECT_CLIENT        Connect to firmware Feature (client).
-
-       usage:
-               struct mei_connect_client_data clientData;
-               ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &clientData);
-
-       inputs:
-               mei_connect_client_data struct contain the following
-               input field:
-
-               in_client_uuid -        UUID of the FW Feature that needs
-                                       to connect to.
-       outputs:
-               out_client_properties - Client Properties: MTU and Protocol Version.
-
-       error returns:
-               EINVAL  Wrong IOCTL Number
-               ENODEV  Device or Connection is not initialized or ready.
-                       (e.g. Wrong UUID)
-               ENOMEM  Unable to allocate memory to client internal data.
-               EFAULT  Fatal Error (e.g. Unable to access user input data)
-               EBUSY   Connection Already Open
-
-       Notes:
-        max_msg_length (MTU) in client properties describes the maximum
-        data that can be sent or received. (e.g. if MTU=2K, can send
-        requests up to bytes 2k and received responses upto 2k bytes).
-
-Intel ME Applications:
-==============
-
-1) Intel Local Management Service (Intel LMS)
-
-       Applications running locally on the platform communicate with Intel AMT Release
-       2.0 and later releases in the same way that network applications do via SOAP
-       over HTTP (deprecated starting with Release 6.0) or with WS-Management over
-       SOAP over HTTP. This means that some Intel AMT features can be accessed from a
-       local application using the same network interface as a remote application
-       communicating with Intel AMT over the network.
-
-       When a local application sends a message addressed to the local Intel AMT host
-       name, the Intel LMS, which listens for traffic directed to the host name,
-       intercepts the message and routes it to the Intel MEI.
-       For more information:
-       http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-       Under "About Intel AMT" => "Local Access"
-
-       For downloading Intel LMS:
-       http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/
-
-       The Intel LMS opens a connection using the Intel MEI driver to the Intel LMS
-       firmware feature using a defined UUID and then communicates with the feature
-       using a protocol called Intel AMT Port Forwarding Protocol(Intel APF protocol).
-       The protocol is used to maintain multiple sessions with Intel AMT from a
-       single application.
-
-       See the protocol specification in the Intel AMT Software Development Kit(SDK)
-       http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-       Under "SDK Resources" => "Intel(R) vPro(TM) Gateway(MPS)"
-       => "Information for Intel(R) vPro(TM) Gateway Developers"
-       => "Description of the Intel AMT Port Forwarding (APF)Protocol"
-
-  2) Intel AMT Remote configuration using a Local Agent
-       A Local Agent enables IT personnel to configure Intel AMT out-of-the-box
-       without requiring installing additional data to enable setup. The remote
-       configuration process may involve an ISV-developed remote configuration
-       agent that runs on the host.
-       For more information:
-       http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide
-       Under "Setup and Configuration of Intel AMT" =>
-       "SDK Tools Supporting Setup and Configuration" =>
-       "Using the Local Agent Sample"
-
-       An open source Intel AMT configuration utility, implementing a local agent
-       that accesses the Intel MEI driver, can be found here:
-       http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/
-
-
-Intel AMT OS Health Watchdog:
-=============================
-The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog.
-Whenever the OS hangs or crashes, Intel AMT will send an event
-to any subscriber to this event. This mechanism means that
-IT knows when a platform crashes even when there is a hard failure on the host.
-
-The Intel AMT Watchdog is composed of two parts:
-       1) Firmware feature - receives the heartbeats
-          and sends an event when the heartbeats stop.
-       2) Intel MEI driver - connects to the watchdog feature, configures the
-          watchdog and sends the heartbeats.
-
-The Intel MEI driver uses the kernel watchdog to configure the Intel AMT
-Watchdog and to send heartbeats to it. The default timeout of the
-watchdog is 120 seconds.
-
-If the Intel AMT Watchdog feature does not exist (i.e. the connection failed),
-the Intel MEI driver will disable the sending of heartbeats.
-
-Supported Chipsets:
-==================
-7 Series Chipset Family
-6 Series Chipset Family
-5 Series Chipset Family
-4 Series Chipset Family
-Mobile 4 Series Chipset Family
-ICH9
-82946GZ/GL
-82G35 Express
-82Q963/Q965
-82P965/G965
-Mobile PM965/GM965
-Mobile GME965/GLE960
-82Q35 Express
-82G33/G31/P35/P31 Express
-82Q33 Express
-82X38/X48 Express
-
----
-linux-mei@linux.intel.com
diff --git a/drivers/staging/mei/mei_dev.h b/drivers/staging/mei/mei_dev.h
deleted file mode 100644 (file)
index 10b1b4e..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-
-#ifndef _MEI_DEV_H_
-#define _MEI_DEV_H_
-
-#include <linux/types.h>
-#include <linux/watchdog.h>
-#include "mei.h"
-#include "hw.h"
-
-/*
- * watch dog definition
- */
-#define MEI_WATCHDOG_DATA_SIZE         16
-#define MEI_START_WD_DATA_SIZE         20
-#define MEI_WD_PARAMS_SIZE             4
-#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT       (1 << 0)
-
-#define MEI_RD_MSG_BUF_SIZE           (128 * sizeof(u32))
-
-/*
- * MEI PCI Device object
- */
-extern struct pci_dev *mei_device;
-
-
-/*
- * AMTHI Client UUID
- */
-extern const uuid_le mei_amthi_guid;
-
-/*
- * Watchdog Client UUID
- */
-extern const uuid_le mei_wd_guid;
-
-/*
- * Watchdog independence state message
- */
-extern const u8 mei_wd_state_independence_msg[3][4];
-
-/*
- * Number of File descriptors/handles
- * that can be opened to the driver.
- *
- * Limit to 253: 255 Total Clients
- * minus internal client for AMTHI
- * minus internal client for Watchdog
- */
-#define  MEI_MAX_OPEN_HANDLE_COUNT     253
-
-/*
- * Number of Maximum MEI Clients
- */
-#define MEI_CLIENTS_MAX 255
-
-/* File state */
-enum file_state {
-       MEI_FILE_INITIALIZING = 0,
-       MEI_FILE_CONNECTING,
-       MEI_FILE_CONNECTED,
-       MEI_FILE_DISCONNECTING,
-       MEI_FILE_DISCONNECTED
-};
-
-/* MEI device states */
-enum mei_states {
-       MEI_INITIALIZING = 0,
-       MEI_INIT_CLIENTS,
-       MEI_ENABLED,
-       MEI_RESETING,
-       MEI_DISABLED,
-       MEI_RECOVERING_FROM_RESET,
-       MEI_POWER_DOWN,
-       MEI_POWER_UP
-};
-
-/* init clients states*/
-enum mei_init_clients_states {
-       MEI_START_MESSAGE = 0,
-       MEI_ENUM_CLIENTS_MESSAGE,
-       MEI_CLIENT_PROPERTIES_MESSAGE
-};
-
-enum iamthif_states {
-       MEI_IAMTHIF_IDLE,
-       MEI_IAMTHIF_WRITING,
-       MEI_IAMTHIF_FLOW_CONTROL,
-       MEI_IAMTHIF_READING,
-       MEI_IAMTHIF_READ_COMPLETE
-};
-
-enum mei_file_transaction_states {
-       MEI_IDLE,
-       MEI_WRITING,
-       MEI_WRITE_COMPLETE,
-       MEI_FLOW_CONTROL,
-       MEI_READING,
-       MEI_READ_COMPLETE
-};
-
-/* MEI CB */
-enum mei_cb_major_types {
-       MEI_READ = 0,
-       MEI_WRITE,
-       MEI_IOCTL,
-       MEI_OPEN,
-       MEI_CLOSE
-};
-
-/*
- * Intel MEI message data struct
- */
-struct mei_message_data {
-       u32 size;
-       unsigned char *data;
-} __packed;
-
-
-struct mei_cl_cb {
-       struct list_head cb_list;
-       enum mei_cb_major_types major_file_operations;
-       void *file_private;
-       struct mei_message_data request_buffer;
-       struct mei_message_data response_buffer;
-       unsigned long information;
-       unsigned long read_time;
-       struct file *file_object;
-};
-
-/* MEI client instance carried as file->pirvate_data*/
-struct mei_cl {
-       struct list_head link;
-       struct mei_device *dev;
-       enum file_state state;
-       wait_queue_head_t tx_wait;
-       wait_queue_head_t rx_wait;
-       wait_queue_head_t wait;
-       int read_pending;
-       int status;
-       /* ID of client connected */
-       u8 host_client_id;
-       u8 me_client_id;
-       u8 mei_flow_ctrl_creds;
-       u8 timer_count;
-       enum mei_file_transaction_states reading_state;
-       enum mei_file_transaction_states writing_state;
-       int sm_state;
-       struct mei_cl_cb *read_cb;
-};
-
-struct mei_io_list {
-       struct mei_cl_cb mei_cb;
-};
-
-/* MEI private device struct */
-struct mei_device {
-       struct pci_dev *pdev;   /* pointer to pci device struct */
-       /*
-        * lists of queues
-        */
-        /* array of pointers to aio lists */
-       struct mei_io_list read_list;           /* driver read queue */
-       struct mei_io_list write_list;          /* driver write queue */
-       struct mei_io_list write_waiting_list;  /* write waiting queue */
-       struct mei_io_list ctrl_wr_list;        /* managed write IOCTL list */
-       struct mei_io_list ctrl_rd_list;        /* managed read IOCTL list */
-       struct mei_io_list amthi_cmd_list;      /* amthi list for cmd waiting */
-
-       /* driver managed amthi list for reading completed amthi cmd data */
-       struct mei_io_list amthi_read_complete_list;
-       /*
-        * list of files
-        */
-       struct list_head file_list;
-       long open_handle_count;
-       /*
-        * memory of device
-        */
-       unsigned int mem_base;
-       unsigned int mem_length;
-       void __iomem *mem_addr;
-       /*
-        * lock for the device
-        */
-       struct mutex device_lock; /* device lock */
-       struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
-       bool recvd_msg;
-       /*
-        * 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;
-
-       /*
-        * mei device  states
-        */
-       enum mei_states mei_state;
-       enum mei_init_clients_states init_clients_state;
-       u16 init_clients_timer;
-       bool stop;
-       bool need_reset;
-
-       u32 extra_write_index;
-       unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];  /* 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;
-
-       struct mei_me_client *me_clients; /* Note: memory has to be allocated */
-       DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
-       DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
-       u8 me_clients_num;
-       u8 me_client_presentation_num;
-       u8 me_client_index;
-       bool mei_host_buffer_is_empty;
-
-       struct mei_cl wd_cl;
-       bool wd_pending;
-       bool wd_stopped;
-       bool wd_bypass; /* if false, don't refresh watchdog ME client */
-       u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
-       u16 wd_due_counter;
-       unsigned char wd_data[MEI_START_WD_DATA_SIZE];
-
-
-
-       struct file *iamthif_file_object;
-       struct mei_cl iamthif_cl;
-       struct mei_cl_cb *iamthif_current_cb;
-       int iamthif_mtu;
-       unsigned long iamthif_timer;
-       u32 iamthif_stall_timer;
-       unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */
-       u32 iamthif_msg_buf_size;
-       u32 iamthif_msg_buf_index;
-       enum iamthif_states iamthif_state;
-       bool iamthif_flow_control_pending;
-       bool iamthif_ioctl;
-       bool iamthif_canceled;
-
-       bool wd_interface_reg;
-};
-
-
-/*
- * mei init function prototypes
- */
-struct mei_device *mei_device_init(struct pci_dev *pdev);
-void mei_reset(struct mei_device *dev, int interrupts);
-int mei_hw_init(struct mei_device *dev);
-int mei_task_initialize_clients(void *data);
-int mei_initialize_clients(struct mei_device *dev);
-int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl);
-void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id);
-void mei_host_init_iamthif(struct mei_device *dev);
-void mei_allocate_me_clients_storage(struct mei_device *dev);
-
-
-u8 mei_find_me_client_update_filext(struct mei_device *dev,
-                               struct mei_cl *priv,
-                               const uuid_le *cguid, u8 client_id);
-
-/*
- * MEI IO List Functions
- */
-void mei_io_list_init(struct mei_io_list *list);
-void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl);
-
-/*
- * MEI ME Client Functions
- */
-
-struct mei_cl *mei_cl_allocate(struct mei_device *dev);
-void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
-int mei_cl_flush_queues(struct mei_cl *cl);
-/**
- * mei_cl_cmp_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns true  - if ids are the same and not NULL
- */
-static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
-                               const struct mei_cl *cl2)
-{
-       return cl1 && cl2 &&
-               (cl1->host_client_id == cl2->host_client_id) &&
-               (cl1->me_client_id == cl2->me_client_id);
-}
-
-
-
-/*
- * MEI Host Client Functions
- */
-void mei_host_start_message(struct mei_device *dev);
-void mei_host_enum_clients_message(struct mei_device *dev);
-int mei_host_client_properties(struct mei_device *dev);
-
-/*
- *  MEI interrupt functions prototype
- */
-irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id);
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
-void mei_timer(struct work_struct *work);
-
-/*
- *  MEI input output function prototype
- */
-int mei_ioctl_connect_client(struct file *file,
-                       struct mei_connect_client_data *data);
-
-int mei_start_read(struct mei_device *dev, struct mei_cl *cl);
-
-int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb);
-
-int amthi_read(struct mei_device *dev, struct file *file,
-             char __user *ubuf, size_t length, loff_t *offset);
-
-struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev,
-                                               struct file *file);
-
-void mei_run_next_iamthif_cmd(struct mei_device *dev);
-
-void mei_free_cb_private(struct mei_cl_cb *priv_cb);
-
-int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
-
-/*
- * Register Access Function
- */
-
-/**
- * mei_reg_read - Reads 32bit data from the mei device
- *
- * @dev: the device structure
- * @offset: offset from which to read the data
- *
- * returns register value (u32)
- */
-static inline u32 mei_reg_read(struct mei_device *dev, unsigned long offset)
-{
-       return ioread32(dev->mem_addr + offset);
-}
-
-/**
- * mei_reg_write - Writes 32bit data to the mei device
- *
- * @dev: the device structure
- * @offset: offset from which to write the data
- * @value: register value to write (u32)
- */
-static inline void mei_reg_write(struct mei_device *dev,
-                               unsigned long offset, u32 value)
-{
-       iowrite32(value, dev->mem_addr + offset);
-}
-
-/**
- * mei_hcsr_read - Reads 32bit data from the host CSR
- *
- * @dev: the device structure
- *
- * returns the byte read.
- */
-static inline u32 mei_hcsr_read(struct mei_device *dev)
-{
-       return mei_reg_read(dev, H_CSR);
-}
-
-/**
- * mei_mecsr_read - Reads 32bit data from the ME CSR
- *
- * @dev: the device structure
- *
- * returns ME_CSR_HA register value (u32)
- */
-static inline u32 mei_mecsr_read(struct mei_device *dev)
-{
-       return mei_reg_read(dev, ME_CSR_HA);
-}
-
-/**
- * get_me_cb_rw - Reads 32bit data from the mei ME_CB_RW register
- *
- * @dev: the device structure
- *
- * returns ME_CB_RW register value (u32)
- */
-static inline u32 mei_mecbrw_read(struct mei_device *dev)
-{
-       return mei_reg_read(dev, ME_CB_RW);
-}
-
-
-/*
- * mei interface function prototypes
- */
-void mei_hcsr_set(struct mei_device *dev);
-void mei_csr_clear_his(struct mei_device *dev);
-
-void mei_enable_interrupts(struct mei_device *dev);
-void mei_disable_interrupts(struct mei_device *dev);
-
-#endif
diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c
deleted file mode 100644 (file)
index 1e62851..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/watchdog.h>
-
-#include "mei_dev.h"
-#include "hw.h"
-#include "interface.h"
-#include "mei.h"
-
-static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
-static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
-
-const u8 mei_wd_state_independence_msg[3][4] = {
-       {0x05, 0x02, 0x51, 0x10},
-       {0x05, 0x02, 0x52, 0x10},
-       {0x07, 0x02, 0x01, 0x10}
-};
-
-/*
- * AMT Watchdog Device
- */
-#define INTEL_AMT_WATCHDOG_ID "INTCAMT"
-
-/* UUIDs for AMT F/W clients */
-const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
-                                               0x9D, 0xA9, 0x15, 0x14, 0xCB,
-                                               0x32, 0xAB);
-
-static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
-{
-       dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
-       memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
-       memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16));
-}
-
-/**
- * host_init_wd - mei initialization wd.
- *
- * @dev: the device structure
- * returns -ENENT if wd client cannot be found
- *         -EIO if write has failed
- */
-int mei_wd_host_init(struct mei_device *dev)
-{
-       mei_cl_init(&dev->wd_cl, dev);
-
-       /* look for WD client and connect to it */
-       dev->wd_cl.state = MEI_FILE_DISCONNECTED;
-       dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT;
-
-       /* find ME WD client */
-       mei_find_me_client_update_filext(dev, &dev->wd_cl,
-                               &mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
-
-       dev_dbg(&dev->pdev->dev, "wd: check client\n");
-       if (MEI_FILE_CONNECTING != dev->wd_cl.state) {
-               dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
-               return -ENOENT;
-       }
-
-       if (mei_connect(dev, &dev->wd_cl)) {
-               dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
-               dev->wd_cl.state = MEI_FILE_DISCONNECTED;
-               dev->wd_cl.host_client_id = 0;
-               return -EIO;
-       }
-       dev->wd_cl.timer_count = CONNECT_TIMEOUT;
-
-       return 0;
-}
-
-/**
- * mei_wd_send - sends watch dog message to fw.
- *
- * @dev: the device structure
- *
- * returns 0 if success,
- *     -EIO when message send fails
- *     -EINVAL when invalid message is to be sent
- */
-int mei_wd_send(struct mei_device *dev)
-{
-       struct mei_msg_hdr *mei_hdr;
-
-       mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
-       mei_hdr->host_addr = dev->wd_cl.host_client_id;
-       mei_hdr->me_addr = dev->wd_cl.me_client_id;
-       mei_hdr->msg_complete = 1;
-       mei_hdr->reserved = 0;
-
-       if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
-               mei_hdr->length = MEI_START_WD_DATA_SIZE;
-       else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
-               mei_hdr->length = MEI_WD_PARAMS_SIZE;
-       else
-               return -EINVAL;
-
-       return mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length);
-}
-
-/**
- * mei_wd_stop - sends watchdog stop message to fw.
- *
- * @dev: the device structure
- * @preserve: indicate if to keep the timeout value
- *
- * returns 0 if success,
- *     -EIO when message send fails
- *     -EINVAL when invalid message is to be sent
- */
-int mei_wd_stop(struct mei_device *dev, bool preserve)
-{
-       int ret;
-       u16 wd_timeout = dev->wd_timeout;
-
-       cancel_delayed_work(&dev->timer_work);
-       if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
-               return 0;
-
-       dev->wd_timeout = 0;
-       dev->wd_due_counter = 0;
-       memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
-       dev->stop = true;
-
-       ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
-       if (ret < 0)
-               goto out;
-
-       if (ret && dev->mei_host_buffer_is_empty) {
-               ret = 0;
-               dev->mei_host_buffer_is_empty = false;
-
-               if (!mei_wd_send(dev)) {
-                       ret = mei_flow_ctrl_reduce(dev, &dev->wd_cl);
-                       if (ret)
-                               goto out;
-               } else {
-                       dev_err(&dev->pdev->dev, "wd: send stop failed\n");
-               }
-
-               dev->wd_pending = false;
-       } else {
-               dev->wd_pending = true;
-       }
-       dev->wd_stopped = false;
-       mutex_unlock(&dev->device_lock);
-
-       ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
-                                       dev->wd_stopped, 10 * HZ);
-       mutex_lock(&dev->device_lock);
-       if (dev->wd_stopped) {
-               dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
-               ret = 0;
-       } else {
-               if (!ret)
-                       ret = -ETIMEDOUT;
-               dev_warn(&dev->pdev->dev,
-                       "wd: stop failed to complete ret=%d.\n", ret);
-       }
-
-       if (preserve)
-               dev->wd_timeout = wd_timeout;
-
-out:
-       return ret;
-}
-
-/*
- * mei_wd_ops_start - wd start command from the watchdog core.
- *
- * @wd_dev - watchdog device struct
- *
- * returns 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_start(struct watchdog_device *wd_dev)
-{
-       int err = -ENODEV;
-       struct mei_device *dev;
-
-       dev = pci_get_drvdata(mei_device);
-       if (!dev)
-               return -ENODEV;
-
-       mutex_lock(&dev->device_lock);
-
-       if (dev->mei_state != MEI_ENABLED) {
-               dev_dbg(&dev->pdev->dev,
-                       "wd: mei_state != MEI_ENABLED  mei_state = %d\n",
-                       dev->mei_state);
-               goto end_unlock;
-       }
-
-       if (dev->wd_cl.state != MEI_FILE_CONNECTED)     {
-               dev_dbg(&dev->pdev->dev,
-                       "MEI Driver is not connected to Watchdog Client\n");
-               goto end_unlock;
-       }
-
-       mei_wd_set_start_timeout(dev, dev->wd_timeout);
-
-       err = 0;
-end_unlock:
-       mutex_unlock(&dev->device_lock);
-       return err;
-}
-
-/*
- * mei_wd_ops_stop -  wd stop command from the watchdog core.
- *
- * @wd_dev - watchdog device struct
- *
- * returns 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
-{
-       struct mei_device *dev;
-       dev = pci_get_drvdata(mei_device);
-
-       if (!dev)
-               return -ENODEV;
-
-       mutex_lock(&dev->device_lock);
-       mei_wd_stop(dev, false);
-       mutex_unlock(&dev->device_lock);
-
-       return 0;
-}
-
-/*
- * mei_wd_ops_ping - wd ping command from the watchdog core.
- *
- * @wd_dev - watchdog device struct
- *
- * returns 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
-{
-       int ret = 0;
-       struct mei_device *dev;
-       dev = pci_get_drvdata(mei_device);
-
-       if (!dev)
-               return -ENODEV;
-
-       mutex_lock(&dev->device_lock);
-
-       if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
-               dev_err(&dev->pdev->dev, "wd: not connected.\n");
-               ret = -ENODEV;
-               goto end;
-       }
-
-       /* Check if we can send the ping to HW*/
-       if (dev->mei_host_buffer_is_empty &&
-               mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
-
-               dev->mei_host_buffer_is_empty = false;
-               dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
-
-               if (mei_wd_send(dev)) {
-                       dev_err(&dev->pdev->dev, "wd: send failed.\n");
-                       ret = -EIO;
-                       goto end;
-               }
-
-               if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) {
-                       dev_err(&dev->pdev->dev,
-                               "wd: mei_flow_ctrl_reduce() failed.\n");
-                       ret = -EIO;
-                       goto end;
-               }
-
-       } else {
-               dev->wd_pending = true;
-       }
-
-end:
-       mutex_unlock(&dev->device_lock);
-       return ret;
-}
-
-/*
- * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
- *
- * @wd_dev - watchdog device struct
- * @timeout - timeout value to set
- *
- * returns 0 if success, negative errno code for failure
- */
-static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
-{
-       struct mei_device *dev;
-       dev = pci_get_drvdata(mei_device);
-
-       if (!dev)
-               return -ENODEV;
-
-       /* Check Timeout value */
-       if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT)
-               return -EINVAL;
-
-       mutex_lock(&dev->device_lock);
-
-       dev->wd_timeout = timeout;
-       wd_dev->timeout = timeout;
-       mei_wd_set_start_timeout(dev, dev->wd_timeout);
-
-       mutex_unlock(&dev->device_lock);
-
-       return 0;
-}
-
-/*
- * Watchdog Device structs
- */
-static const struct watchdog_ops wd_ops = {
-               .owner = THIS_MODULE,
-               .start = mei_wd_ops_start,
-               .stop = mei_wd_ops_stop,
-               .ping = mei_wd_ops_ping,
-               .set_timeout = mei_wd_ops_set_timeout,
-};
-static const struct watchdog_info wd_info = {
-               .identity = INTEL_AMT_WATCHDOG_ID,
-               .options = WDIOF_KEEPALIVEPING,
-};
-
-static struct watchdog_device amt_wd_dev = {
-               .info = &wd_info,
-               .ops = &wd_ops,
-               .timeout = AMT_WD_DEFAULT_TIMEOUT,
-               .min_timeout = AMT_WD_MIN_TIMEOUT,
-               .max_timeout = AMT_WD_MAX_TIMEOUT,
-};
-
-
-void  mei_watchdog_register(struct mei_device *dev)
-{
-       dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout);
-
-       dev->wd_due_counter = !!dev->wd_timeout;
-
-       if (watchdog_register_device(&amt_wd_dev)) {
-               dev_err(&dev->pdev->dev,
-                       "wd: unable to register watchdog device.\n");
-               dev->wd_interface_reg = false;
-       } else {
-               dev_dbg(&dev->pdev->dev,
-                       "wd: successfully register watchdog interface.\n");
-               dev->wd_interface_reg = true;
-       }
-}
-
-void mei_watchdog_unregister(struct mei_device *dev)
-{
-       if (dev->wd_interface_reg)
-               watchdog_unregister_device(&amt_wd_dev);
-       dev->wd_interface_reg = false;
-}
-