Skip to contentSkip to conversation

Intel Management Engine Interface

PATCH In review Anas Nashif 7 participants 8 messages May 20, 2008 – May 23, 2008 Char and misc drivers

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Intel Management Engine Interface

We have addressed more issues raised on lkml after initial submission, especially the legacy device support issue which was removed in this patch.

The Intel Management Engine Interface (aka HECI: Host Embedded Controller Interface ) enables communication between the host OS and the Management Engine firmware. MEI is bi-directional, and either the host or Intel AMT firmware can initiate transactions.

The core hardware architecture of Intel Active Management Technology (Intel AMT) is resident in firmware. The micro-controller within the chipset's graphics and memory controller (GMCH) hub houses the Management Engine (ME) firmware, which implements various services on behalf of management applications.

Some of the ME subsystems that can be access via MEI driver:

- Intel(R) Quiet System Technology (QST) is implemented as a firmware subsystem that runs in the ME. Programs that wish to expose the health monitoring and fan speed control capabilities of Intel(R) QST will need to use the MEI driver to communicate with the ME sub-system.
- ASF is the "Alert Standard Format" which is an DMTF manageability standard. It is implemented in the PC's hardware and firmware, and is managed from a remote console.

Most recent Intel desktop chipsets have one or more of the above ME services. The MEI driver will make it possible to support the above features on Linux and provides applications access to the ME and it's features.

---

MAINTAINERS +9 -0
index e467758..5b8d2cd 100644
@@ -2082,6 +2082,15 @@ L:	[email protected]
 W:	http://e1000.sourceforge.net/
 S:	Supported
 
+INTEL MANAGEABILITY ENGINE INTERFACE (HECI)
+P:	Anas Nashif
+M: 	[email protected]
+P:	Marcin Obara
+M:	[email protected]
+W:	http://www.openamt.org/
+L:	[email protected]
+S:	Supported
+
 INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
 P:	Zhu Yi
 M:	[email protected]
drivers/char/Kconfig +1 -0
index 47c6be8..249f97e 100644
@@ -1048,6 +1048,7 @@ config DEVPORT
 	default y
 
 source "drivers/s390/char/Kconfig"
+source "drivers/char/heci/Kconfig"
 
 endmenu
 
drivers/char/Makefile +1 -0
index 5407b76..26c81a0 100644
@@ -106,6 +106,7 @@ obj-$(CONFIG_IPMI_HANDLER)	+= ipmi/
 
 obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM)		+= tpm/
+obj-$(CONFIG_HECI)              += heci/
 
 obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
 
drivers/char/heci/Kconfig new file +12 -0
new file mode 100644
index 0000000..a4d8bf4
@@ -0,0 +1,12 @@
+#
+# HECI device configuration
+#
+
+config INTEL_MEI
+       tristate "Intel Management Engine Interface (MEI) Support"
+       depends on EXPERIMENTAL
+       ---help---
+         The Intel Management Engine Interface (Intel MEI) driver allows
+         applications to access the Active Management Technology
+         firmware and other Management Engine sub-systems.
+
drivers/char/heci/Makefile new file +7 -0
new file mode 100644
index 0000000..a2d7182
@@ -0,0 +1,7 @@
+#
+## Makefile for the Intel MEI driver (heci)
+#
+
+obj-$(CONFIG_INTEL_MEI) += heci.o
+
+heci-objs := heci_init.o heci_interface.o heci_main.o interrupt.o io_heci.o
drivers/char/heci/heci.h new file +184 -0

184 lines not on this page · raw message

(quoted diff) +0 -0

b/drivers/char/heci/heci_data_structures.h
new file mode 100644
index 0000000..ac0f488

drivers/char/heci/heci_data_structures.h new file +507 -0

507 lines not on this page · raw message

drivers/char/heci/heci_init.c new file +1104 -0

1,104 lines not on this page · raw message

drivers/char/heci/heci_interface.c new file +497 -0

497 lines not on this page · raw message

drivers/char/heci/heci_interface.h new file +169 -0

169 lines not on this page · raw message

drivers/char/heci/heci_main.c new file +1544 -0

491 lines not on this page · raw message

drivers/char/heci/heci_version.h new file +56 -0

56 lines not on this page · raw message

drivers/char/heci/interrupt.c new file +1551 -0

1,551 lines not on this page · raw message

drivers/char/heci/io_heci.c new file +865 -0

865 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#1 lore raw
Quoted 25 lines · On Mon, 19 May 2008 20:11:54 -0400 Anas Nashif <[email protected]> wrote:

We have addressed more issues raised on lkml after initial submission, especially the legacy device support issue which was removed in this patch.

The Intel Management Engine Interface (aka HECI: Host Embedded Controller Interface ) enables communication between the host OS and the Management Engine firmware. MEI is bi-directional, and either the host or Intel AMT firmware can initiate transactions.

The core hardware architecture of Intel Active Management Technology (Intel AMT) is resident in firmware. The micro-controller within the chipset's graphics and memory controller (GMCH) hub houses the Management Engine (ME) firmware, which implements various services on behalf of management applications.

Some of the ME subsystems that can be access via MEI driver:

- Intel(R) Quiet System Technology (QST) is implemented as a firmware subsystem that runs in the ME. Programs that wish to expose the health monitoring and fan speed control capabilities of Intel(R) QST will need to use the MEI driver to communicate with the ME sub-system.
- ASF is the "Alert Standard Format" which is an DMTF manageability standard. It is implemented in the PC's hardware and firmware, and is managed from a remote console.

Quoted 4 lines

Most recent Intel desktop chipsets have one or more of the above ME services. The MEI driver will make it possible to support the above features on Linux and provides applications access to the ME and it's features.

What a lot of code.

It'd be nice if the changelog were to describe the proposed and all-important kernel<->userspace interface, please. From a five-second peek it looks like a miscdev with ioctls? Ah, and there's read and write too.

What is the payload for those system calls, and the meanings of their return values, etc, etc?

Does it make sense for this driver to be available on all architectures?

#4 lore raw
In reply to Anas Nashif
Quoted 15 lines · On Tuesday, 20 May 2008 03:11:54 Anas Nashif wrote:

We have addressed more issues raised on lkml after initial submission, especially the legacy device support issue which was removed in this patch.

The Intel Management Engine Interface (aka HECI: Host Embedded Controller Interface ) enables communication between the host OS and the Management Engine firmware. MEI is bi-directional, and either the host or Intel AMT firmware can initiate transactions.

The core hardware architecture of Intel Active Management Technology (Intel AMT) is resident in firmware. The micro-controller within the chipset's graphics and memory controller (GMCH) hub houses the Management Engine (ME) firmware, which implements various services on behalf of management applications.

Quoted 6 lines

Some of the ME subsystems that can be access via MEI driver:

- Intel(R) Quiet System Technology (QST) is implemented as a firmware subsystem that runs in the ME. Programs that wish to expose the health monitoring and fan speed control capabilities of Intel(R) QST will need to use the MEI driver to communicate with the ME sub-system.

I bought a system with intel DG965RY motherboard year ago, and still no support for its O/B sensors in linux.

Can I ask again, when you expect it to be released.
At least intel should release documents how to access the QST sensors.

I know that HECI is first step for that, but it is not enought to read those sensors.

I Really hope there are good news,
Best regards,
Maxim Levitsky

#2 lore raw
In reply to Andrew Morton
Quoted 40 lines · Andrew Morton
Quoted 25 lines · On Mon, 19 May 2008 20:11:54 -0400 Anas Nashif <[email protected]> wrote:

We have addressed more issues raised on lkml after initial submission, especially the legacy device support issue which was removed in this patch.

The Intel Management Engine Interface (aka HECI: Host Embedded Controller Interface ) enables communication between the host OS and the Management Engine firmware. MEI is bi-directional, and either the host or Intel AMT firmware can initiate transactions.

The core hardware architecture of Intel Active Management Technology (Intel AMT) is resident in firmware. The micro-controller within the chipset's graphics and memory controller (GMCH) hub houses the Management Engine (ME) firmware, which implements various services on behalf of management applications.

Some of the ME subsystems that can be access via MEI driver:

- Intel(R) Quiet System Technology (QST) is implemented as a firmware subsystem that runs in the ME. Programs that wish to expose the health monitoring and fan speed control capabilities of Intel(R) QST will need to use the MEI driver to communicate with the ME sub-system.
- ASF is the "Alert Standard Format" which is an DMTF manageability standard. It is implemented in the PC's hardware and firmware, and is managed from a remote console.

Quoted 4 lines

Most recent Intel desktop chipsets have one or more of the above ME services. The MEI driver will make it possible to support the above features on Linux and provides applications access to the ME and it's features.

What a lot of code.

It'd be nice if the changelog were to describe the proposed and all-important kernel<->userspace interface, please. From a five-second peek it looks like a miscdev with ioctls? Ah, and there's read and write too.

Quoted 5 lines

What is the payload for those system calls, and the meanings of their return values, etc, etc?

Does it make sense for this driver to be available on all architectures?

This patch is against what tree / kernel version ?

Won't compile on current kernels cause it still uses class_device_* so I guess it is based on 2.6.22/23 ?

Also in drivers/char/Makefile $(CONFIG_HECI) should be $(CONFIG_INTEL_MEI)

Gabriel

#5 lore raw
In reply to Anas Nashif

drivers/char/heci/heci_data_structures.h line 198

Quoted 8 lines
drivers/char/heci/heci_data_structures.h new file +3 -0
[...]
 
+#define SECOND_TO_MILLI                 1000
+#define SECOND_TO_MICRO                 SECOND_TO_MILLI * 1000
+#define SECOND_TO_100NANO               SECOND_TO_MICRO * 10

These definitions are not used in any file, why don't you remove them?

#6 lore raw
In reply to Anas Nashif
Quoted 8 lines · Anas Nashif

We have addressed more issues raised on lkml after initial submission, especially the legacy device support issue which was removed in this patch.

The Intel Management Engine Interface (aka HECI: Host Embedded Controller Interface ) enables communication between the host OS and the Management Engine firmware. MEI is bi-directional, and either the host or Intel AMT firmware can initiate transactions.

[...]

drivers/char/Makefile obj-$(CONFIG_IPMI_HANDLER) += ipmi/ · line 109

Quoted 9 lines
drivers/char/Makefile +1 -0
index 5407b76..26c81a0 100644
@@ -106,6 +106,7 @@ obj-$(CONFIG_IPMI_HANDLER)	+= ipmi/
 
 obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM)		+= tpm/
+obj-$(CONFIG_HECI)              += heci/

Who sets this config up?

Quoted 3 lines
drivers/char/Makefile +0 -0
 obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
 

[...]

Quoted 6 lines
drivers/char/heci/heci_init.c new file +0 -0
new file mode 100644
index 0000000..ffd4f7f
@@ -0,0 +1,1104 @@

[...]

drivers/char/heci/heci_init.c line 234

Quoted 9 lines
drivers/char/heci/heci_init.c new file +9 -0
+static int heci_wait_event_int_timeout(struct iamt_heci_device *dev,
+		long timeout)
+{
+	int err = 0;
+
+	err = wait_event_interruptible_timeout(dev->wait_recvd_msg,
+			(dev->recvd_msg), timeout);
+	return err;
+}

return wait_event_interruptible_timeout();

[...]

Quoted 10 lines
drivers/char/heci/heci_init.c new file +10 -0
+static int host_start_message(struct iamt_heci_device *dev)
+{
+	long timeout = 60;	/* 60 second */
+
+	struct heci_msg_hdr *heci_hdr;
+	struct hbm_host_version_request *host_start_req;
+	struct hbm_host_stop_request *host_stop_req;
+	int err = 0;
+
+	/* host start message */

drivers/char/heci/heci_init.c line 537

Quoted 10 lines
drivers/char/heci/heci_init.c new file +10 -0
+	heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
+	heci_hdr->host_addr = 0;
+	heci_hdr->me_addr = 0;
+	heci_hdr->length = sizeof(struct hbm_host_version_request);
+	heci_hdr->msg_complete = 1;
+	heci_hdr->reserved = 0;
+
+	host_start_req =
+	    (struct hbm_host_version_request *) &dev->wr_msg_buf[1];
+	memset(host_start_req, 0, sizeof(host_start_req));

wrong memset

Quoted 23 lines
drivers/char/heci/heci_init.c new file +23 -0
+	host_start_req->cmd.cmd = HOST_START_REQ_CMD;
+	host_start_req->reserved = 0;
+	host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
+	host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
+	dev->recvd_msg = 0;
+	if (!heci_write_message(dev, heci_hdr,
+				       (unsigned char *) (host_start_req),
+				       heci_hdr->length)) {
+		DBG("send version to fw fail.\n");
+		return -ENODEV;
+	}
+	DBG("call wait_event_interruptible_timeout for response message.\n");
+	/* wait for response */
+	err = heci_wait_event_int_timeout(dev, timeout * HZ);
+	if (!err && !dev->recvd_msg) {
+		DBG("wait_timeout failed on host start response message.\n");
+		return -ENODEV;
+	}
+	dev->recvd_msg = 0;
+	DBG("wait_timeout successful on host start response message.\n");
+	if ((dev->version.major_version != HBM_MAJOR_VERSION) ||
+	    (dev->version.minor_version != HBM_MINOR_VERSION)) {
+		/* send stop message */

drivers/char/heci/heci_init.c line 570

Quoted 10 lines
drivers/char/heci/heci_init.c new file +10 -0
+		heci_hdr->host_addr = 0;
+		heci_hdr->me_addr = 0;
+		heci_hdr->length = sizeof(struct hbm_host_stop_request);
+		heci_hdr->msg_complete = 1;
+		heci_hdr->reserved = 0;
+
+		host_stop_req =
+		    (struct hbm_host_stop_request *) &dev->wr_msg_buf[1];
+
+		memset(host_stop_req, 0, sizeof(host_stop_req));

same here

Quoted 13 lines
drivers/char/heci/heci_init.c new file +13 -0
+		host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
+		host_stop_req->reason = DRIVER_STOP_REQUEST;
+		memset(host_stop_req->reserved, 0,
+		       sizeof(host_stop_req->reserved));
+		heci_write_message(dev, heci_hdr,
+				   (unsigned char *) (host_stop_req),
+				   heci_hdr->length);
+		DBG("version mismatch.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}

[...]

Quoted 35 lines
drivers/char/heci/heci_init.c new file +35 -0
+static void host_init_wd(struct iamt_heci_device *dev)
+{
+
+	spin_lock_bh(&dev->device_lock);
+
+	heci_init_file_private(&dev->wd_file_ext, NULL);
+
+	/* look for WD client and connect to it */
+	dev->wd_file_ext.state = HECI_FILE_DISCONNECTED;
+	dev->wd_timeout = 0;
+
+	heci_check_asf_mode(dev);
+	if (dev->asf_mode) {
+		memcpy(dev->wd_data, stop_wd_params, HECI_WD_PARAMS_SIZE);
+	} else {
+		/* AMT mode */
+		dev->wd_timeout = AMT_WD_VALUE;
+		DBG("dev->wd_timeout=%d.\n", dev->wd_timeout);
+		memcpy(dev->wd_data, start_wd_params, HECI_WD_PARAMS_SIZE);
+		memcpy(dev->wd_data + HECI_WD_PARAMS_SIZE,
+		       &dev->wd_timeout, sizeof(__u16));
+	}
+
+	/* find ME WD client */
+	heci_find_me_client(dev, &dev->wd_file_ext,
+			    &heci_wd_guid, HECI_WD_HOST_CLIENT_ID);
+	spin_unlock_bh(&dev->device_lock);
+
+	DBG("check wd_file_ext\n");
+	if (HECI_FILE_CONNECTING == dev->wd_file_ext.state) {
+		if (heci_connect_me_client(dev, &dev->wd_file_ext, 15) == 1) {
+			DBG("dev->wd_timeout=%d.\n", dev->wd_timeout);
+			if (dev->wd_timeout != 0)
+				dev->wd_due_counter = 1;
+			else

drivers/char/heci/heci_init.c line 928

Quoted 10 lines
drivers/char/heci/heci_init.c new file +10 -0
+				dev->wd_due_counter = 0;
+			DBG("successfully connected to WD client.\n");
+		}
+	} else
+		DBG("failed to find WD client.\n");
+
+
+	spin_lock_bh(&dev->device_lock);
+	dev->wd_timer.function = &heci_wd_timer;
+	dev->wd_timer.data = (unsigned long) dev;

setup_timer?

Quoted 2 lines
drivers/char/heci/heci_init.c new file +2 -0
+	spin_unlock_bh(&dev->device_lock);
+}

[...]

Quoted 1 line

+struct heci_file_private *alloc_priv(struct file *file)

not a good name.

Quoted 1 line

+{

[...]

drivers/char/heci/heci_init.c line 1020

Quoted 4 lines
drivers/char/heci/heci_init.c new file +4 -0
+int heci_disconnect_host_client(struct iamt_heci_device *dev,
+		struct heci_file_private *file_ext)
+{
+	int rets = 0, err = 0;

no need to init them

Quoted 2 lines
drivers/char/heci/heci_init.c new file +2 -0
+	long timeout = 15;	/*15 second */
+	struct heci_cb_private *priv_cb = NULL;

[...]

Quoted 6 lines
drivers/char/heci/heci_interface.c new file +0 -0
new file mode 100644
index 0000000..6369dd0
@@ -0,0 +1,497 @@

[...]

Quoted 15 lines
drivers/char/heci/heci_interface.c new file +15 -0
+int flow_ctrl_creds(struct iamt_heci_device *dev,
+				   struct heci_file_private *file_ext)
+{
+	__u8 i;
+
+	if (!dev->num_heci_me_clients)
+		return 0;
+
+	if (file_ext == NULL)
+		return 0;
+
+	if (file_ext->flow_ctrl_creds > 0)
+		return 1;
+
+	for (i = 0; i < dev->num_heci_me_clients; i++) {

drivers/char/heci/heci_interface.c line 287

Quoted 10 lines
drivers/char/heci/heci_interface.c new file +10 -0
+		if (dev->me_clients[i].client_id == file_ext->me_client_id) {
+			if (dev->me_clients[i].flow_ctrl_creds > 0) {
+				BUG_ON(dev->me_clients[i].props.single_recv_buf
+					 == 0);
+				return 1;
+			}
+			return 0;
+		}
+	}
+	BUG_ON(1);

So just BUG();

Quoted 20 lines
drivers/char/heci/heci_interface.c new file +20 -0
+	return 0;
+}
+
+/**
+ * flow_ctrl_reduce  - reduce flow_control .
+ *
+ * @dev -Device object for our driver
+ * @file_ext -extension of the file object
+ */
+void flow_ctrl_reduce(struct iamt_heci_device *dev,
+			 struct heci_file_private *file_ext)
+{
+	__u8 i;
+
+	if (!dev->num_heci_me_clients)
+		return;
+
+	for (i = 0; i < dev->num_heci_me_clients; i++) {
+		if (dev->me_clients[i].client_id == file_ext->me_client_id) {
+			if (dev->me_clients[i].props.single_recv_buf != 0) {

drivers/char/heci/heci_interface.c line 317

Quoted 10 lines
drivers/char/heci/heci_interface.c new file +10 -0
+				BUG_ON(dev->me_clients[i].flow_ctrl_creds <= 0);
+				dev->me_clients[i].flow_ctrl_creds--;
+			} else {
+				BUG_ON(file_ext->flow_ctrl_creds <= 0);
+				file_ext->flow_ctrl_creds--;
+			}
+			return;
+		}
+	}
+	BUG_ON(1);

ditto

Quoted 17 lines
drivers/char/heci/heci_interface.c new file +17 -0
+}
+
+/**
+ * heci_send_flow_control  - send flow control to fw.
+ *
+ * @dev -Device object for our driver
+ * @file_ext -extension of the file object
+ *
+ * @return :
+ * 1 if success
+ * 0 - otherwise.
+ */
+int heci_send_flow_control(struct iamt_heci_device *dev,
+				 struct heci_file_private *file_ext)
+{
+	struct heci_msg_hdr *heci_hdr;
+	struct hbm_flow_control *heci_flow_control;

drivers/char/heci/heci_interface.c line 344

Quoted 10 lines
drivers/char/heci/heci_interface.c new file +10 -0
+
+	heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
+	heci_hdr->host_addr = 0;
+	heci_hdr->me_addr = 0;
+	heci_hdr->length = sizeof(struct hbm_flow_control);
+	heci_hdr->msg_complete = 1;
+	heci_hdr->reserved = 0;
+
+	heci_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
+	memset(heci_flow_control, 0, sizeof(heci_flow_control));

again?

Quoted 3 lines
drivers/char/heci/heci_interface.c new file +3 -0
+	heci_flow_control->host_addr = file_ext->host_client_id;
+	heci_flow_control->me_addr = file_ext->me_client_id;
+	heci_flow_control->cmd.cmd = FLOW_CONTROL_CMD;

[...]

Quoted 6 lines
drivers/char/heci/heci_interface.h new file +0 -0
new file mode 100644
index 0000000..4081fd3
@@ -0,0 +1,169 @@

[...]

drivers/char/heci/heci_interface.h line 93

Quoted 2 lines
drivers/char/heci/heci_interface.h new file +2 -0
+/* IOCTL commands */
+#define HECI_IOCTL_LETTER 'H'

'H' all linux/hiddev.h

add

drivers/char/heci/heci_interface.h line 103

Quoted 8 lines
drivers/char/heci/heci_interface.h new file +8 -0
+#define IOCTL_HECI_GET_VERSION \
+    _IOWR(HECI_IOCTL_LETTER , 0x800, struct heci_message_data)
+#define IOCTL_HECI_CONNECT_CLIENT \
+    _IOWR(HECI_IOCTL_LETTER , 0x801, struct heci_message_data)
+#define IOCTL_HECI_WD \
+    _IOWR(HECI_IOCTL_LETTER , 0x802, struct heci_message_data)
+#define IOCTL_HECI_BYPASS_WD \
+    _IOWR(HECI_IOCTL_LETTER , 0x810, struct heci_message_data)

struct heci_message_data is not 32/64-bit friendly _IOC_NRBITS is 8, 0x800 is far higher than that

[...]

Quoted 6 lines
drivers/char/heci/heci_main.c new file +0 -0
new file mode 100644
index 0000000..608e1c7
@@ -0,0 +1,1544 @@

[...]

drivers/char/heci/heci_main.c line 87

Quoted 4 lines
drivers/char/heci/heci_main.c new file +4 -0
+#ifdef HECI_DEBUG
+int heci_debug = 1;
+#else
+int heci_debug;  /* initialized to 0 automatically.*/

we know that, comment unneeded

drivers/char/heci/heci_main.c line 89

Quoted 2 lines
drivers/char/heci/heci_main.c new file +2 -0
+#endif
+MODULE_PARM_DESC(heci_debug,  "Debug enabled or not");

so why not bool?

Quoted 3 lines
drivers/char/heci/heci_main.c new file +3 -0
+module_param(heci_debug, int, 0644);
+
+

[...]

Quoted 16 lines
drivers/char/heci/heci_main.c new file +16 -0
+/* heci_pci_tbl - PCI Device ID Table */
+static struct pci_device_id heci_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID01)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID02)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID03)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID04)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID05)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID06)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID07)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID08)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID09)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID10)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID11)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID12)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID13)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID14)},

drivers/char/heci/heci_main.c line 132

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID15)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID16)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID17)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID18)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID19)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID20)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID21)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID22)},
+	/* required last entry */
+	{0, }

PCI_VDEVICE?

[...]

drivers/char/heci/heci_main.c line 169

Quoted 5 lines
drivers/char/heci/heci_main.c new file +5 -0
+static struct pci_driver heci_driver = {
+	.name = heci_driver_name,
+	.id_table = heci_pci_tbl,
+	.probe = heci_probe,
+	.remove = heci_remove,

__devexit_p()

drivers/char/heci/heci_main.c line 170

Quoted 1 line
drivers/char/heci/heci_main.c new file +1 -0
+	.shutdown = heci_remove,

you'll trigger remove twice, I think.

drivers/char/heci/heci_main.c line 174

Quoted 4 lines
drivers/char/heci/heci_main.c new file +4 -0
+#ifdef CONFIG_PM
+	.suspend = heci_suspend,
+	.resume = heci_resume
+#endif

define them as null on !PM to avoid these ifdefs.

Quoted 1 line

+};

[...]

drivers/char/heci/heci_main.c line 202

Quoted 4 lines
drivers/char/heci/heci_main.c new file +4 -0
+static int heci_registration_cdev(struct cdev *dev, int hminor,
+				  struct file_operations *fops)
+{
+	int ret = 0, devno = MKDEV(heci_major, hminor);

do not init ret

drivers/char/heci/heci_main.c line 206

Quoted 4 lines
drivers/char/heci/heci_main.c new file +4 -0
+
+	cdev_init(dev, fops);
+	dev->owner = THIS_MODULE;
+	dev->ops = fops;

no need to re-set

drivers/char/heci/heci_main.c line 210

Quoted 4 lines
drivers/char/heci/heci_main.c new file +4 -0
+	ret = cdev_add(dev, devno, 1);
+	/* Fail gracefully if need be */
+	if (ret) {
+		kobject_put(&dev->kobj);

why?

Quoted 9 lines
drivers/char/heci/heci_main.c new file +9 -0
+		printk(KERN_ERR "%s: Error %d registering heci device %d\n",
+		       THIS_MODULE->name, ret, hminor);
+	}
+	return ret;
+}
+
+/* Display the version of heci driver. */
+static ssize_t version_show(struct class *dev, char *buf)
+{

drivers/char/heci/heci_main.c line 229

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+	return sprintf(buf, "%s %s.\n",
+		       heci_driver_string, heci_driver_version);
+}
+
+static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
+
+/**
+ * heci_sysfs_create - creates a struct class to contain heci info
+ * @owner  - pointer to the module that is to "own" heci sysfs class
+ * @name   - pointer to a string for the name of this class

the format is:
(* @parameterx(space)*: (description of parameter x)?)*

Quoted 6 lines

+ *
+ * @return :
+ * valid pointer to a struct class on success
+ * false pointer on failure
+ */
+static struct class *heci_sysfs_create(struct module *owner, char *name)

[...]

Quoted 11 lines
drivers/char/heci/heci_main.c new file +11 -0
+/**
+ * heci_sysfs_device_create - adds two devices to sysfs for chararcter devices
+ * @cs      - pointer to the struct class that the device to be registered on
+ *
+ * @return :
+ * 0 on success,
+ * negative on failure
+ */
+static int heci_sysfs_device_create(struct class *cs)
+{
+	int err = 0;

drivers/char/heci/heci_main.c line 292

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+
+	if ((cs == NULL) || (IS_ERR(cs))) {
+		err = -EINVAL;
+		goto err_out;
+	}
+
+	heci_class_dev = class_device_create(cs, NULL,
+					     heci_cdev.dev,
+					     NULL,
+					     HECI_DEV_NAME);

device_create

Quoted 6 lines
drivers/char/heci/heci_main.c new file +6 -0
+	if (IS_ERR(heci_class_dev))
+		err = PTR_ERR(heci_class_dev);
+
+err_out:
+	return err;
+}

[...]

Quoted 7 lines
drivers/char/heci/heci_main.c new file +7 -0
+static int __init heci_init_module(void)
+{
+	int ret = 0;
+	dev_t dev;
+
+	printk(KERN_INFO "%s: %s - version %s\n",
+	       THIS_MODULE->name, heci_driver_string, heci_driver_version);

drivers/char/heci/heci_main.c line 335

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+	printk(KERN_INFO "%s: %s\n", THIS_MODULE->name, heci_copyright);
+
+	/* init pci module */
+	ret = pci_register_driver(&heci_driver);
+	if (ret < 0)
+		goto end;
+
+	/* registration char devices */
+	ret = alloc_chrdev_region(&dev, HECI_MINORS_BASE, HECI_MINORS_COUNT,
+				  HECI_DRIVER_NAME);

just one minor? why not misc_register?

Quoted 2 lines
drivers/char/heci/heci_main.c new file +2 -0
+
+	heci_major = MAJOR(dev);

[...]

Quoted 65 lines
drivers/char/heci/heci_main.c new file +65 -0
+static int __devinit heci_probe(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
+{
+	struct iamt_heci_device *dev = NULL;
+	int i, err = 0;
+
+	if (heci_device) {
+		err = -EEXIST;
+		goto end;
+	}
+	/* enable pci dev */
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s: Failed to enable pci device.\n",
+		       THIS_MODULE->name);
+		goto end;
+	}
+	/* set PCI host mastering  */
+	pci_set_master(pdev);
+	/* pci request regions for heci driver */
+	err = pci_request_regions(pdev, heci_driver_name);
+	if (err) {
+		printk(KERN_ERR "%s: Failed to get pci regions.\n",
+		       THIS_MODULE->name);
+		goto disable_device;
+	}
+	/* allocates and initializes the heci dev structure */
+	dev = init_heci_device(pdev);
+	if (!dev) {
+		err = -ENOMEM;
+		goto release_regions;
+	}
+	/* mapping  IO device memory */
+	for (i = BAR_0; i <= BAR_5; i++) {
+		if (pci_resource_len(pdev, i) == 0)
+			continue;
+		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
+			printk(KERN_ERR "%s: heci has an IO ports.\n",
+			       THIS_MODULE->name);
+			goto free_device;
+		} else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+			if (dev->mem_base) {
+				printk(KERN_ERR "%s: Too many mem addresses.\n",
+				       THIS_MODULE->name);
+				goto free_device;
+			}
+			dev->mem_base = pci_resource_start(pdev, i);
+			dev->mem_length = pci_resource_len(pdev, i);
+		}
+	}
+	if (!dev->mem_base) {
+		printk(KERN_ERR "%s: No address to use.\n", THIS_MODULE->name);
+		err = -ENODEV;
+		goto free_device;
+	}
+	dev->mem_addr = ioremap_nocache(dev->mem_base,
+			dev->mem_length);
+	if (!dev->mem_addr) {
+		printk(KERN_ERR "%s: Remap IO device memory failure.\n",
+		       THIS_MODULE->name);
+		err = -ENOMEM;
+		goto free_device;
+	}
+	/* request and enable interrupt   */
+	dev->irq = pdev->irq;

drivers/char/heci/heci_main.c line 480

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+	err = request_irq(dev->irq, heci_isr_interrupt, IRQF_SHARED,
+			heci_driver_name, dev);
+	if (err) {
+		printk(KERN_ERR "%s: Request_irq failure. irq = %d \n",
+		       THIS_MODULE->name, dev->irq);
+		goto unmap_memory;
+	}
+
+	if (heci_hw_init(dev)) {
+		printk(KERN_ERR "%s: Init hw failure.\n", THIS_MODULE->name);

This can be built tristate, right? What if THIS_MODULE is 0.

Use dev_* prints anyway.

drivers/char/heci/heci_main.c line 484

Quoted 4 lines
drivers/char/heci/heci_main.c new file +4 -0
+		err = -ENODEV;
+		goto release_irq;
+	}
+	init_timer(&dev->wd_timer);

not needed, if heci_initialize_clients called setup_timer

Quoted 6 lines
drivers/char/heci/heci_main.c new file +6 -0
+	msleep(100); /* FW needs time to be ready to talk with us */
+	heci_initialize_clients(dev);
+	if (dev->heci_state != HECI_ENABLED) {
+		err = -ENODEV;
+		goto release_hw;
+	}

[...]

Quoted 34 lines
drivers/char/heci/heci_main.c new file +34 -0
+static void __devexit heci_remove(struct pci_dev *pdev)
+{
+	struct iamt_heci_device *dev = pci_get_drvdata(pdev);
+	int err = 0;
+
+	if (heci_device != pdev)
+		return;
+
+	if (dev == NULL)
+		return;
+
+	spin_lock_bh(&dev->device_lock);
+	if (dev->reinit_tsk != NULL) {
+		kthread_stop(dev->reinit_tsk);
+		dev->reinit_tsk = NULL;
+	}
+	spin_unlock_bh(&dev->device_lock);
+
+	del_timer_sync(&dev->wd_timer);
+	if (dev->wd_file_ext.state == HECI_FILE_CONNECTED
+	    && dev->wd_timeout) {
+		spin_lock_bh(&dev->device_lock);
+		dev->wd_timeout = 0;
+		dev->wd_due_counter = 0;
+		memcpy(dev->wd_data, stop_wd_params, HECI_WD_PARAMS_SIZE);
+		dev->stop = 1;
+		if (dev->host_buffer_is_empty &&
+		    flow_ctrl_creds(dev, &dev->wd_file_ext)) {
+			dev->host_buffer_is_empty = 0;
+
+			if (!heci_send_wd(dev))
+				DBG("send stop WD failed\n");
+			else
+				flow_ctrl_reduce(dev, &dev->wd_file_ext);

drivers/char/heci/heci_main.c line 585

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+
+			dev->wd_pending = 0;
+		} else {
+			dev->wd_pending = 1;
+		}
+		spin_unlock_bh(&dev->device_lock);
+		dev->wd_stoped = 0;
+
+		err = wait_event_interruptible_timeout(dev->wait_stop_wd,
+				(dev->wd_stoped), 10 * HZ);

What is the retval for?

Quoted 29 lines
drivers/char/heci/heci_main.c new file +29 -0
+		if (!dev->wd_stoped)
+			DBG("stop wd failed to complete.\n");
+		else
+			DBG("stop wd complete.\n");
+
+	}
+
+	heci_device = NULL;
+	if (dev->iamthif_file_ext.status == HECI_FILE_CONNECTED) {
+		dev->iamthif_file_ext.status = HECI_FILE_DISCONNECTING;
+		heci_disconnect_host_client(dev,
+					    &dev->iamthif_file_ext);
+	}
+	if (dev->wd_file_ext.status == HECI_FILE_CONNECTED) {
+		dev->wd_file_ext.status = HECI_FILE_DISCONNECTING;
+		heci_disconnect_host_client(dev,
+					    &dev->wd_file_ext);
+	}
+
+	spin_lock_bh(&dev->device_lock);
+
+	/* remove entry if already in list */
+	DBG("list del iamthif and wd file list.\n");
+	heci_remove_client_from_file_list(dev, dev->wd_file_ext.
+					  host_client_id);
+	heci_remove_client_from_file_list(dev,
+			dev->iamthif_file_ext.host_client_id);
+
+	dev->iamthif_current_cb = NULL;

drivers/char/heci/heci_main.c line 624

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+	dev->iamthif_file_ext.file = NULL;
+	dev->num_heci_me_clients = 0;
+
+	spin_unlock_bh(&dev->device_lock);
+
+	flush_scheduled_work();
+	/* disable interrupts */
+	dev->host_hw_state &= ~H_IE;
+	/* acknowledge interrupt and stop interupts */
+	write_heci_register(dev, H_CSR, dev->host_hw_state);

PCI posting?

Quoted 11 lines
drivers/char/heci/heci_main.c new file +11 -0
+	free_irq(pdev->irq, dev);
+	pci_set_drvdata(pdev, NULL);
+
+	if (dev->mem_addr)
+		iounmap(dev->mem_addr);
+
+	kfree(dev);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}

[...]

drivers/char/heci/heci_main.c line 902

Quoted 6 lines
drivers/char/heci/heci_main.c new file +6 -0
+static ssize_t heci_read(struct file *file, char __user *ubuf,
+			 size_t length, loff_t *offset)
+{
+	int i;
+	int rets = 0, err = 0;
+	int if_num = MINOR((file->f_dentry->d_inode->i_rdev));

iminor?

Quoted 120 lines
drivers/char/heci/heci_main.c new file +120 -0
+	struct heci_file_private *file_ext = file->private_data;
+	struct heci_cb_private *priv_cb_pos = NULL;
+	struct heci_cb_private *priv_cb = NULL;
+	struct iamt_heci_device *dev = NULL;
+
+	if (!heci_device)
+		return -ENODEV;
+
+	dev = pci_get_drvdata(heci_device);
+	if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
+		return -ENODEV;
+
+	spin_lock_bh(&dev->device_lock);
+	if (dev->heci_state != HECI_ENABLED) {
+		spin_unlock_bh(&dev->device_lock);
+		return -ENODEV;
+	}
+	spin_unlock_bh(&dev->device_lock);
+
+	spin_lock(&file_ext->file_lock);
+	if ((file_ext->sm_state & HECI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
+		spin_unlock(&file_ext->file_lock);
+		/* Do not allow to read watchdog client */
+		for (i = 0; i < dev->num_heci_me_clients; i++) {
+			if (memcmp(&heci_wd_guid,
+				   &dev->me_clients[i].props.protocol_name,
+				   sizeof(struct guid)) == 0) {
+				if (file_ext->me_client_id ==
+				    dev->me_clients[i].client_id)
+					return -EBADF;
+			}
+		}
+	} else {
+		file_ext->sm_state &= ~HECI_WD_STATE_INDEPENDENCE_MSG_SENT;
+		spin_unlock(&file_ext->file_lock);
+	}
+
+	if (file_ext == &dev->iamthif_file_ext) {
+		rets = pthi_read(dev, if_num, file, ubuf, length, offset);
+		goto out;
+	}
+
+	if (file_ext->read_cb && file_ext->read_cb->information > *offset) {
+		priv_cb = file_ext->read_cb;
+		goto copy_buffer;
+	} else if (file_ext->read_cb && file_ext->read_cb->information > 0 &&
+		   file_ext->read_cb->information <= *offset) {
+		priv_cb = file_ext->read_cb;
+		rets = 0;
+		goto free;
+	} else if ((!file_ext->read_cb || file_ext->read_cb->information == 0)
+		    && *offset > 0) {
+		/*Offset needs to be cleaned for contingous reads*/
+		*offset = 0;
+		rets = 0;
+		goto out;
+	}
+
+	spin_lock(&file_ext->read_io_lock);
+	err = heci_start_read(dev, if_num, file_ext);
+	if (err != 0 && err != -EBUSY) {
+		DBG("heci start read failure with status = %d\n", err);
+		spin_unlock(&file_ext->read_io_lock);
+		rets = err;
+		goto out;
+	}
+	if (HECI_READ_COMPLETE != file_ext->reading_state
+			&& !waitqueue_active(&file_ext->rx_wait)) {
+		if (file->f_flags & O_NONBLOCK) {
+			rets = -EAGAIN;
+			spin_unlock(&file_ext->read_io_lock);
+			goto out;
+		}
+		spin_unlock(&file_ext->read_io_lock);
+
+		if (wait_event_interruptible(file_ext->rx_wait,
+			(HECI_READ_COMPLETE == file_ext->reading_state
+			 || HECI_FILE_INITIALIZING == file_ext->state
+			 || HECI_FILE_DISCONNECTED == file_ext->state
+			 || HECI_FILE_DISCONNECTING == file_ext->state))) {
+			if (signal_pending(current)) {
+				rets = -EINTR;
+				goto out;
+			}
+			return -ERESTARTSYS;
+		}
+
+		if (HECI_FILE_INITIALIZING == file_ext->state ||
+		    HECI_FILE_DISCONNECTED == file_ext->state ||
+		    HECI_FILE_DISCONNECTING == file_ext->state) {
+			rets = -EBUSY;
+			goto out;
+		}
+		spin_lock(&file_ext->read_io_lock);
+	}
+
+	priv_cb = file_ext->read_cb;
+
+	if (!priv_cb) {
+		spin_unlock(&file_ext->read_io_lock);
+		return -ENODEV;
+	}
+	if (file_ext->reading_state != HECI_READ_COMPLETE) {
+		spin_unlock(&file_ext->read_io_lock);
+		return 0;
+	}
+	spin_unlock(&file_ext->read_io_lock);
+	/* now copy the data to user space */
+copy_buffer:
+	DBG("priv_cb->response_buffer size - %d\n",
+	    priv_cb->response_buffer.size);
+	DBG("priv_cb->information - %lu\n",
+	    priv_cb->information);
+	if (length == 0 || ubuf == NULL ||
+	    *offset > priv_cb->information) {
+		rets = -EMSGSIZE;
+		goto free;
+	}
+
+	/* length is being turncated to PAGE_SIZE, however, */

drivers/char/heci/heci_main.c line 1032

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+	/* information size may be longer */
+	length = (length < (priv_cb->information - *offset) ?
+			length : (priv_cb->information - *offset));
+
+	if (copy_to_user(ubuf,
+			 priv_cb->response_buffer.data + *offset,
+			 length)) {
+		rets = -EFAULT;
+		goto free;
+	} else {

no need to 'else' here

Quoted 31 lines
drivers/char/heci/heci_main.c new file +31 -0
+		rets = length;
+		*offset += length;
+		if ((unsigned long)*offset < priv_cb->information)
+			goto out;
+	}
+free:
+	spin_lock_bh(&dev->device_lock);
+	priv_cb_pos = find_read_list_entry(dev, file_ext);
+	/* Remove entry from read list */
+	if (priv_cb_pos != NULL)
+		list_del(&priv_cb_pos->cb_list);
+	spin_unlock_bh(&dev->device_lock);
+	heci_free_cb_private(priv_cb);
+	spin_lock(&file_ext->read_io_lock);
+	file_ext->reading_state = HECI_IDLE;
+	file_ext->read_cb = NULL;
+	file_ext->read_pending = 0;
+	spin_unlock(&file_ext->read_io_lock);
+out:	DBG("end heci read rets= %d\n", rets);
+	return rets;
+}
+
+/**
+ * heci_write - the write function.
+ */
+static ssize_t heci_write(struct file *file, const char __user *ubuf,
+			  size_t length, loff_t *offset)
+{
+	int rets = 0;
+	__u8 i;
+	int if_num = MINOR((file->f_dentry->d_inode->i_rdev));

...

Quoted 5 lines
drivers/char/heci/heci_main.c new file +5 -0
+	struct heci_file_private *file_ext = file->private_data;
+	struct heci_cb_private *priv_write_cb = NULL;
+	struct heci_msg_hdr heci_hdr;
+	struct iamt_heci_device *dev = NULL;
+	unsigned long currtime = get_seconds();

[...]

drivers/char/heci/heci_main.c line 1315

Quoted 2 lines
drivers/char/heci/heci_main.c new file +2 -0
+static int heci_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long data)

->unlocked_ioctl

Quoted 8 lines
drivers/char/heci/heci_main.c new file +8 -0
+{
+	int rets = 0;
+	int if_num = MINOR(inode->i_rdev);
+	struct heci_file_private *file_ext = file->private_data;
+	/* in user space */
+	struct heci_message_data *u_msg = (struct heci_message_data *) data;
+	struct heci_message_data k_msg;	/* all in kernel on the stack */
+	struct iamt_heci_device *dev = NULL;

[...]

Quoted 51 lines
drivers/char/heci/heci_main.c new file +51 -0
+#ifdef CONFIG_PM
+static int heci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct iamt_heci_device *device = pci_get_drvdata(pdev);
+	int err = 0;
+
+	spin_lock_bh(&device->device_lock);
+	if (device->reinit_tsk != NULL) {
+		kthread_stop(device->reinit_tsk);
+		device->reinit_tsk = NULL;
+	}
+	spin_unlock_bh(&device->device_lock);
+
+	/* Stop watchdog if exists */
+	del_timer_sync(&device->wd_timer);
+	if (device->wd_file_ext.state == HECI_FILE_CONNECTED
+	    && device->wd_timeout) {
+		spin_lock_bh(&device->device_lock);
+		g_sus_wd_timeout = device->wd_timeout;
+		device->wd_timeout = 0;
+		device->wd_due_counter = 0;
+		memcpy(device->wd_data, stop_wd_params, HECI_WD_PARAMS_SIZE);
+		device->stop = 1;
+		if (device->host_buffer_is_empty &&
+		    flow_ctrl_creds(device, &device->wd_file_ext)) {
+			device->host_buffer_is_empty = 0;
+			if (!heci_send_wd(device))
+				DBG("send stop WD failed\n");
+			else
+				flow_ctrl_reduce(device, &device->wd_file_ext);
+
+			device->wd_pending = 0;
+		} else {
+			device->wd_pending = 1;
+		}
+		spin_unlock_bh(&device->device_lock);
+		device->wd_stoped = 0;
+
+		err = wait_event_interruptible_timeout(device->wait_stop_wd,
+						       (device->wd_stoped),
+						       10 * HZ);
+		if (!device->wd_stoped)
+			DBG("stop wd failed to complete.\n");
+		else {
+			DBG("stop wd complete %d.\n", err);
+			err = 0;
+		}
+	}
+	/* Set new heci state */
+	spin_lock_bh(&device->device_lock);
+	if (device->heci_state == HECI_ENABLED ||

drivers/char/heci/heci_main.c line 1489

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+	    device->heci_state == HECI_RECOVERING_FROM_RESET) {
+		device->heci_state = HECI_POWER_DOWN;
+		heci_reset(device, 0);
+	}
+	spin_unlock_bh(&device->device_lock);
+
+	pci_save_state(pdev);
+
+	pci_disable_device(pdev);
+	free_irq(pdev->irq, device);

no device irq disabling?

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	return err;
+}
+
+static int heci_resume(struct pci_dev *pdev)
+{
+	struct iamt_heci_device *device = NULL;
+	int err = 0;

drivers/char/heci/heci_main.c line 1509

Quoted 10 lines
drivers/char/heci/heci_main.c new file +10 -0
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	device = pci_get_drvdata(pdev);
+	if (!device)
+		return -ENODEV;
+
+	/* request and enable interrupt   */
+	device->irq = pdev->irq;

so why do you need the copy of an irq?

Quoted 7 lines
drivers/char/heci/heci_main.c new file +7 -0
+	err = request_irq(device->irq, heci_isr_interrupt, IRQF_SHARED,
+			heci_driver_name, device);
+	if (err) {
+		printk(KERN_ERR "%s: Request_irq failure. irq = %d \n",
+		       THIS_MODULE->name, device->irq);
+		return err;
+	}

[...]

Quoted 6 lines
drivers/char/heci/heci_version.h new file +0 -0
new file mode 100644
index 0000000..6cbb5e2
@@ -0,0 +1,56 @@

[...]

drivers/char/heci/heci_version.h line 52

Quoted 12 lines
drivers/char/heci/heci_version.h new file +12 -0
+#ifndef HECI_VERSION_H
+#define HECI_VERSION_H
+
+#define MAJOR_VERSION              5
+#define MINOR_VERSION              0
+#define QUICK_FIX_NUMBER        0
+#define VER_BUILD               1
+
+#define str(s) name(s)
+#define name(s) #s
+#define DRIVER_V1		str(MAJOR_VERSION) "." str(MINOR_VERSION)
+#define DRIVER_V2		str(QUICK_FIX_NUMBER) "." str(VER_BUILD)

hmm, __stringify()

drivers/char/heci/heci_version.h line 54

Quoted 2 lines
drivers/char/heci/heci_version.h new file +2 -0
+
+#define DRIVER_VERSION	DRIVER_V1 "." DRIVER_V2

not good macro names at all

Quoted 8 lines
drivers/char/heci/heci_version.h new file +2 -0
+
+#endif
drivers/char/heci/interrupt.c new file +0 -0
new file mode 100644
index 0000000..c2fc1d0
@@ -0,0 +1,1551 @@

[...]

Quoted 9 lines
drivers/char/heci/interrupt.c new file +9 -0
+irqreturn_t heci_isr_interrupt(int irq, void *dev_id)
+{
+	int err;
+	struct iamt_heci_device *device = (struct iamt_heci_device *) dev_id;
+	device->host_hw_state = read_heci_register(device, H_CSR);
+
+	if ((device->host_hw_state & H_IS) != H_IS)
+		return IRQ_NONE;
+

drivers/char/heci/interrupt.c line 101

Quoted 10 lines
drivers/char/heci/interrupt.c new file +10 -0
+	/* disable interrupts */
+	device->host_hw_state &= ~H_IE;
+	/* acknowledge interrupt and stop interupts */
+	write_heci_register(device, H_CSR, device->host_hw_state);
+	/**
+	 * Our device interrupted, schedule work the heci_bh_handler
+	 * to handle the interrupt processing. This needs to be a
+	 * workqueue item since the handler can sleep.
+	 */
+	PREPARE_WORK(&device->work, heci_bh_handler);

this is racy with bh?

drivers/char/heci/interrupt.c line 104

Quoted 3 lines
drivers/char/heci/interrupt.c new file +3 -0
+	DBG("schedule work the heci_bh_handler.\n");
+	err = schedule_work(&device->work);
+	if (!err) {

some ratelimit?

Quoted 5 lines
drivers/char/heci/interrupt.c new file +5 -0
+		printk(KERN_ERR "%s: schedule the heci_bh_handler"
+		       " failed error=%x\n", THIS_MODULE->name, err);
+	}
+	return IRQ_HANDLED;
+}

[...]

Quoted 70 lines
drivers/char/heci/interrupt.c new file +70 -0
+static void heci_bh_handler(struct work_struct *work)
+{
+	struct iamt_heci_device *dev =
+		container_of(work, struct iamt_heci_device, work);
+	struct io_heci_list complete_list;
+	__s32 slots;
+	int rets;
+	struct heci_cb_private *cb_pos = NULL, *cb_next = NULL;
+	struct heci_file_private *file_ext = NULL;
+	int bus_message_received = 0;
+	struct task_struct *tsk;
+
+	DBG("function called after ISR to handle the interrupt processing.\n");
+	/* initialize our complete list */
+	spin_lock_bh(&dev->device_lock);
+	heci_initialize_list(&complete_list, dev);
+	dev->host_hw_state = read_heci_register(dev, H_CSR);
+	dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
+
+	/* check if ME wants a reset */
+	if (((dev->me_hw_state & ME_RDY_HRA) == 0)
+	    && (dev->heci_state != HECI_RESETING)
+	    && (dev->heci_state != HECI_INITIALIZING)) {
+		DBG("FW not ready.\n");
+		heci_reset(dev, 1);
+		spin_unlock_bh(&dev->device_lock);
+		return;
+	}
+
+	/*  check if we need to start the dev */
+	if ((dev->host_hw_state & H_RDY) == 0) {
+		if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
+			DBG("we need to start the dev.\n");
+			dev->host_hw_state |= (H_IE | H_IG | H_RDY);
+			write_heci_register(dev, H_CSR, dev->host_hw_state);
+			if (dev->heci_state == HECI_INITIALIZING) {
+				dev->recvd_msg = 1;
+				spin_unlock_bh(&dev->device_lock);
+				wake_up_interruptible(&dev->wait_recvd_msg);
+				return;
+
+			} else {
+				spin_unlock_bh(&dev->device_lock);
+				tsk = kthread_run(heci_task_initialize_clients,
+						  dev, "heci_reinit");
+				if (IS_ERR(tsk)) {
+					int rc = PTR_ERR(tsk);
+					printk(KERN_WARNING "heci: Unable to"
+					"start the heci thread: %d\n", rc);
+				}
+				return;
+			}
+		} else {
+			DBG("enable interrupt FW not ready.\n");
+			dev->host_hw_state |= (H_IE);
+			write_heci_register(dev, H_CSR, dev->host_hw_state);
+			spin_unlock_bh(&dev->device_lock);
+			return;
+		}
+	}
+	/* check slots avalable for reading */
+	slots = count_full_read_slots(dev);
+	DBG("slots =%08x  extra_write_index =%08x.\n",
+		slots, dev->extra_write_index);
+	while ((slots > 0) && (!dev->extra_write_index)) {
+		DBG("slots =%08x  extra_write_index =%08x.\n", slots,
+				dev->extra_write_index);
+		DBG("call heci_bh_read_handler.\n");
+		rets = heci_bh_read_handler(&complete_list, dev, &slots);
+		if (rets != 0)

drivers/char/heci/interrupt.c line 253

Quoted 10 lines
drivers/char/heci/interrupt.c new file +10 -0
+			goto end;
+	}
+	rets = heci_bh_write_handler(&complete_list, dev, &slots);
+end:
+	DBG("end of bottom half function.\n");
+	dev->host_hw_state = read_heci_register(dev, H_CSR);
+	dev->host_buffer_is_empty = host_buffer_is_empty(dev);
+
+	if ((dev->host_hw_state & H_IS) == H_IS) {
+		PREPARE_WORK(&dev->work, heci_bh_handler);

racy with hardirq?

Quoted 6 lines
drivers/char/heci/interrupt.c new file +6 -0
+		DBG("schedule work the heci_bh_handler.\n");
+		rets = schedule_work(&dev->work);
+		if (!rets) {
+			printk(KERN_ERR "%s: schedule the heci_bh_handler"
+			       " failed error=%x\n", THIS_MODULE->name, rets);
+		}

[...]

Quoted 15 lines
drivers/char/heci/interrupt.c new file +15 -0
+static int _heci_bh_ioctl(struct iamt_heci_device *dev,	__s32 *slots,
+			struct heci_cb_private *priv_cb_pos,
+			struct heci_file_private *file_ext,
+			struct io_heci_list *cmpl_list)
+{
+	if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
+			sizeof(struct hbm_client_connect_request))) {
+		file_ext->state = HECI_FILE_CONNECTING;
+		*slots -= (sizeof(struct heci_msg_hdr) +
+			sizeof(struct hbm_client_connect_request) + 3) / 4;
+		if (!heci_connect(dev, file_ext)) {
+			file_ext->status = -ENODEV;
+			priv_cb_pos->information = 0;
+			list_del(&priv_cb_pos->cb_list);
+			return -ENODEV;

drivers/char/heci/interrupt.c line 832

Quoted 10 lines
drivers/char/heci/interrupt.c new file +10 -0
+		} else {
+			list_del(&priv_cb_pos->cb_list);
+			list_add_tail(&priv_cb_pos->cb_list,
+			&dev->ctrl_rd_list.heci_cb.cb_list);
+			file_ext->timer_count = CONNECT_TIMEOUT;
+		}
+	} else {
+		/* return the cancel routine */
+		list_del(&priv_cb_pos->cb_list);
+		return -ECORRUPTED_MESSAGE_HEADER;

Sorry, what?

Quoted 42 lines
drivers/char/heci/interrupt.c new file +42 -0
+	}
+
+	return 0;
+}
+
+/**
+ * _heci_bh_cmpl: process completed and no-iamthif operation.
+ * @dev: device object.
+ * @slots: free slotsl.
+ * @priv_cb_pos: callback block.
+ * @file_ext: file extension.
+ * @cmpl_list: complete list.
+ *
+ * @return :
+ * 0, OK; otherwise, error.
+ */
+static int _heci_bh_cmpl(struct iamt_heci_device *dev,	__s32 *slots,
+			struct heci_cb_private *priv_cb_pos,
+			struct heci_file_private *file_ext,
+			struct io_heci_list *cmpl_list)
+{
+	struct heci_msg_hdr *heci_hdr = NULL;
+
+	if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) +
+			(priv_cb_pos->request_buffer.size -
+			priv_cb_pos->information))) {
+		heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0];
+		heci_hdr->host_addr = file_ext->host_client_id;
+		heci_hdr->me_addr = file_ext->me_client_id;
+		heci_hdr->length = ((priv_cb_pos->request_buffer.size) -
+				(priv_cb_pos->information));
+		heci_hdr->msg_complete = 1;
+		heci_hdr->reserved = 0;
+		DBG("priv_cb_pos->request_buffer.size =%d"
+			"heci_hdr->msg_complete= %d\n",
+				priv_cb_pos->request_buffer.size,
+				heci_hdr->msg_complete);
+		DBG("priv_cb_pos->information  =%lu\n",
+				priv_cb_pos->information);
+		DBG("heci_hdr->length  =%d\n",
+				heci_hdr->length);
+		*slots -= (sizeof(struct heci_msg_hdr) +

drivers/char/heci/interrupt.c line 884

Quoted 10 lines
drivers/char/heci/interrupt.c new file +10 -0
+				heci_hdr->length + 3) / 4;
+		if (!heci_write_message(dev, heci_hdr,
+				(unsigned char *)
+				(priv_cb_pos->request_buffer.data +
+				priv_cb_pos->information),
+				heci_hdr->length)) {
+			file_ext->status = -ENODEV;
+			list_del(&priv_cb_pos->cb_list);
+			list_add_tail(&priv_cb_pos->cb_list,
+				&cmpl_list->heci_cb.cb_list);

list_move_tail?

Quoted 8 lines
drivers/char/heci/interrupt.c new file +8 -0
+			return -ENODEV;
+		} else {
+			flow_ctrl_reduce(dev, file_ext);
+			file_ext->status = 0;
+			priv_cb_pos->information += heci_hdr->length;
+			list_del(&priv_cb_pos->cb_list);
+			list_add_tail(&priv_cb_pos->cb_list,
+				&dev->write_waiting_list.heci_cb.cb_list);

...

Quoted 2 lines
drivers/char/heci/interrupt.c new file +2 -0
+		}
+	} else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {

[...]

drivers/char/heci/interrupt.c line 1347

Quoted 9 lines
drivers/char/heci/interrupt.c new file +9 -0
+static int same_flow_addr(struct heci_file_private *file,
+					struct hbm_flow_control *flow)
+{
+	if ((file->host_client_id == flow->host_addr)
+	    && (file->me_client_id == flow->me_addr))
+		return 1;
+
+	return 0;
+}

just return <the_condition>;

Quoted 7 lines
drivers/char/heci/interrupt.c new file +7 -0
+static void add_single_flow_creds(struct iamt_heci_device *dev,
+				  struct hbm_flow_control *flow)
+{
+	struct heci_me_client *client = NULL;
+	int i;
+
+	for (i = 0; i < dev->num_heci_me_clients; i++) {

drivers/char/heci/interrupt.c line 1370

Quoted 10 lines
drivers/char/heci/interrupt.c new file +10 -0
+		client = &dev->me_clients[i];
+		if (flow->me_addr == client->client_id) {
+			if (client->props.single_recv_buf != 0) {
+				client->flow_ctrl_creds++;
+				DBG("recv flow ctrl msg ME %d (single).\n",
+				    flow->me_addr);
+				DBG("flow control credentials=%d.\n",
+				    client->flow_ctrl_creds);
+			} else {
+				BUG_ON(1);	/* error in flow control */

BUG()

[...]

Quoted 9 lines
drivers/char/heci/interrupt.c new file +9 -0
+static int same_disconn_addr(struct heci_file_private *file,
+			     struct hbm_client_disconnect_request *disconn)
+{
+	if ((file->host_client_id == disconn->host_addr)
+	    && (file->me_client_id == disconn->me_addr))
+		return 1;
+
+	return 0;
+}

...

#7 lore raw
In reply to Anas Nashif

Hi!

Quoted 4 lines

The Intel Management Engine Interface (aka HECI: Host Embedded Controller Interface ) enables communication between the host OS and the Management Engine firmware. MEI is bi-directional, and either the host or Intel AMT firmware can initiate transactions.

* uses homebrewn DBG(), could it use dprintk() or something.

* should probably come with Documentation/ file

* defines like H_IE are a bit too terse.

drivers/char/heci/heci.h line 60

Quoted 5 lines
drivers/char/heci/heci.h new file +5 -0
+extern const struct guid heci_pthi_guid;
+extern const struct guid heci_wd_guid;
+extern const __u8 start_wd_params[];
+extern const __u8 stop_wd_params[];
+extern const __u8 heci_wd_state_independence_msg[2][4];

Externs should go to header file.

No need to use __u8 in kernel.

Variables need good names. pthi_guid is not one of them.

drivers/char/heci/heci.h line 67

Quoted 6 lines
drivers/char/heci/heci.h new file +6 -0
+/**
+ * memory IO BAR definition
+ */
+#define     BAR_0                        0
+#define     BAR_1                        1
+#define     BAR_5                        5

Heh. And comments should tell us what it is.

Hmm, is this kerneldoc? Does not seem like one. So don't use /**. Fix this all over the patch.

Quoted 9 lines

+/**
+ * heci_fe_same_id - tell if file extensions have same id
+ * @fe1 -file extension
+ * @fe2 -file extension
+ *
+ * @return :
+ * 1 - if ids are the same,
+ * 0 - if differ.
+ */

File extensions?!

drivers/char/heci/heci.h line 182

Quoted 10 lines
drivers/char/heci/heci.h new file +10 -0
+static inline int heci_fe_same_id(struct heci_file_private *fe1,
+				  struct heci_file_private *fe2)
+{
+	if ((fe1->host_client_id == fe2->host_client_id)
+	    && (fe1->me_client_id == fe2->me_client_id)) {
+		return 1;
+	} else {
+		return 0;
+	}
+}

This can be written without the if.

Quoted 18 lines
drivers/char/heci/heci.h new file +1 -0
+#endif /* _HECI_H_ */
drivers/char/heci/heci_data_structures.h new file +10 -0
new file mode 100644
index 0000000..ac0f488
@@ -0,0 +1,507 @@
+/*
+ * Part of Intel(R) Manageability Engine Interface Linux driver
+ *
+ * Copyright (c) 2003 - 2008 Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright

drivers/char/heci/heci_data_structures.h line 20

Quoted 10 lines
drivers/char/heci/heci_data_structures.h new file +10 -0
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.

What kind of ninja mutant license is this?

drivers/char/heci/heci_data_structures.h line 66

Quoted 4 lines
drivers/char/heci/heci_data_structures.h new file +4 -0
+/**
+ * Number of queue lists used by this driver
+ */
+#define NUMBER_OF_LISTS        7

Yes, how very useful name. Plus, it is too generic and likely to conflict with someone else.

drivers/char/heci/heci_data_structures.h line 68

Quoted 1 line
drivers/char/heci/heci_data_structures.h new file +1 -0
+#define IAMTHIF_MTU 4160

And this one seems encrypted.

drivers/char/heci/heci_data_structures.h line 79

Quoted 10 lines
drivers/char/heci/heci_data_structures.h new file +10 -0
+
+/**
+ * HECI HW Section
+ */
+
+/* HECI addresses and defines */
+#define H_CB_WW    0
+#define H_CSR      4
+#define ME_CB_RW   8
+#define ME_CSR_HA  0xC

As do this and registers below.

drivers/char/heci/heci_data_structures.h line 124

Quoted 4 lines
drivers/char/heci/heci_data_structures.h new file +4 -0
+/**
+ * time to wait event
+ */
+#define HECI_INTEROP_TIMEOUT    (HZ * 7)

Could we get _useful_ comments?

drivers/char/heci/heci_data_structures.h line 151

Quoted 8 lines
drivers/char/heci/heci_data_structures.h new file +8 -0
+/* File state */
+enum file_state {
+	HECI_FILE_INITIALIZING = 0,
+	HECI_FILE_CONNECTING,
+	HECI_FILE_CONNECTED,
+	HECI_FILE_DISCONNECTING,
+	HECI_FILE_DISCONNECTED
+};

What kind of files is this handling? Surely this is not a filesystem?

drivers/char/heci/heci_data_structures.h line 154

Quoted 2 lines
drivers/char/heci/heci_data_structures.h new file +2 -0
+/* HECI states */
+enum heci_states{

Missing space, and evil comment.
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#3 lore raw
In reply to Andrew Morton

Hi!

Quoted 30 lines
Quoted 25 lines

We have addressed more issues raised on lkml after initial submission, especially the legacy device support issue which was removed in this patch.

The Intel Management Engine Interface (aka HECI: Host Embedded Controller Interface ) enables communication between the host OS and the Management Engine firmware. MEI is bi-directional, and either the host or Intel AMT firmware can initiate transactions.

The core hardware architecture of Intel Active Management Technology (Intel AMT) is resident in firmware. The micro-controller within the chipset's graphics and memory controller (GMCH) hub houses the Management Engine (ME) firmware, which implements various services on behalf of management applications.

Some of the ME subsystems that can be access via MEI driver:

- Intel(R) Quiet System Technology (QST) is implemented as a firmware subsystem that runs in the ME. Programs that wish to expose the health monitoring and fan speed control capabilities of Intel(R) QST will need to use the MEI driver to communicate with the ME sub-system.
- ASF is the "Alert Standard Format" which is an DMTF manageability standard. It is implemented in the PC's hardware and firmware, and is managed from a remote console.

Quoted 4 lines

Most recent Intel desktop chipsets have one or more of the above ME services. The MEI driver will make it possible to support the above features on Linux and provides applications access to the ME and it's features.

Quoted 6 lines

What a lot of code.

It'd be nice if the changelog were to describe the proposed and all-important kernel<->userspace interface, please. From a five-second peek it looks like a miscdev with ioctls? Ah, and there's read and write too.

Actuallly, we already have perfectly good interface for sensor-like stuff -- in lm_sensors. Even acpi is moving in that direction...

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html