File heci_pm_wd_fix.diff of Package intel-iamt-heci

diff -Nur HECI-3.1.0.31/src/heci_data_structures.h HECI-3.2.0.24/src/heci_data_structures.h
--- HECI-3.1.0.31/src/heci_data_structures.h	2007-08-20 10:07:43.000000000 -0400
+++ HECI-3.2.0.24/src/heci_data_structures.h	2008-01-24 07:04:22.000000000 -0500
@@ -153,6 +153,9 @@
 #define HECI_START_WD_DATA_SIZE         20
 #define HECI_WD_PARAMS_SIZE             4
 
+#define HECI_NO_MSG_SENT			0
+#define HECI_WD_STATE_INDEPENDENCE_MSG_SENT 	(1 << 0)
+
 
 #define HECI_WD_HOST_CLIENT_ID          1
 #define HECI_LEGACY_HOST_CLIENT_ID      2
@@ -260,6 +263,7 @@
 	__u8 timer_count;
 	enum heci_file_transaction_states reading_state;
 	enum heci_file_transaction_states writing_state;
+	int sm_state;
 	struct heci_cb_private *read_cb;
 };
 
diff -Nur HECI-3.1.0.31/src/heci.h HECI-3.2.0.24/src/heci.h
--- HECI-3.1.0.31/src/heci.h	2007-08-20 10:07:43.000000000 -0400
+++ HECI-3.2.0.24/src/heci.h	2008-01-24 07:04:21.000000000 -0500
@@ -58,6 +58,7 @@
 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];
 
 /**
  * memory IO BAR definition
diff -Nur HECI-3.1.0.31/src/heci_init.c HECI-3.2.0.24/src/heci_init.c
--- HECI-3.1.0.31/src/heci_init.c	2007-08-20 10:07:43.000000000 -0400
+++ HECI-3.2.0.24/src/heci_init.c	2008-01-24 07:04:22.000000000 -0500
@@ -59,6 +59,9 @@
     { 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
 const __u8 start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
 const __u8 stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
+const __u8 heci_wd_state_independence_msg[2][4] = {
+	{0x05, 0x02, 0x51, 0x10}, 
+	{0x05, 0x02, 0x52, 0x10} };
 const struct guid heci_asf_guid =
     { 0x75B30CD6, 0xA29E, 0x4AF7, {0xA7, 0x12, 0xE6, 0x17, 0x43, 0x93,
 				   0xC8, 0xA6} };
@@ -308,11 +311,19 @@
        struct heci_file_private *file_extension_pos = NULL;
 	struct heci_file_private *file_extension_next = NULL;
 	struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL;
+	int unexpected = 0;
 
 	if (device_object->heci_state == HECI_RECOVERING_FROM_RESET) {
 		device_object->need_reset = TRUE;
 		return;
 	}
+
+	if (device_object->heci_state != HECI_INITIALIZING &&
+	    device_object->heci_state != HECI_DISABLED && 
+		device_object->heci_state != HECI_POWER_DOWN && 
+		device_object->heci_state != HECI_POWER_UP)
+		unexpected = 1; 
+		 
 	device_object->host_hw_state =
 	    read_heci_register(device_object, H_CSR);
 
@@ -346,7 +357,8 @@
 	device_object->need_reset = FALSE;
 
 	if (device_object->heci_state != HECI_INITIALIZING) {
-		if (device_object->heci_state != HECI_DISABLED) {
+		if (device_object->heci_state != HECI_DISABLED && 
+			device_object->heci_state != HECI_POWER_DOWN) {
 			device_object->heci_state = HECI_RESETING;
 		}
 		list_for_each_entry_safe(file_extension_pos, file_extension_next, &device_object->file_list, link) {
@@ -394,8 +406,7 @@
 	DBG("after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
 	    device_object->host_hw_state, device_object->me_hw_state);
 
-	if (device_object->heci_state != HECI_INITIALIZING &&
-	    device_object->heci_state != HECI_DISABLED)
+	if (unexpected)
 		ERR("unexpected heci reset.\n");
 	//Wake up all readings so they can be interrupted
 	list_for_each_entry_safe(file_extension_pos,file_extension_next, &device_object->file_list,link) {
diff -Nur HECI-3.1.0.31/src/heci_main.c HECI-3.2.0.24/src/heci_main.c
--- HECI-3.1.0.31/src/heci_main.c	2007-08-20 10:07:43.000000000 -0400
+++ HECI-3.2.0.24/src/heci_main.c	2008-01-24 07:04:22.000000000 -0500
@@ -99,7 +99,6 @@
 /* The device pointer */
 static struct pci_dev *heci_device;
 
-
 /* heci_pci_tbl - PCI Device ID Table */
 static struct pci_device_id heci_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID1)},
@@ -134,6 +133,11 @@
 static ssize_t heci_write(struct file *file, const char __user * ubuf,
 			  size_t length, loff_t * offset);
 static unsigned int heci_poll(struct file *file, poll_table * wait);
+#ifdef CONFIG_PM
+static int heci_suspend(struct pci_dev* pdev, pm_message_t state);
+static int heci_resume(struct pci_dev* pdev);
+static __u16 g_sus_wd_timeout;
+#endif
 /**
  *  PCI driver structure
  */
@@ -143,6 +147,10 @@
 	.probe = heci_probe,
 	.remove = heci_remove,
 	SHUTDOWN_METHOD(heci_remove)
+#ifdef CONFIG_PM
+	.suspend = heci_suspend, 
+	.resume = heci_resume
+#endif
 };
 
 /**
@@ -370,6 +378,9 @@
 	if (device->wd_timeout) {
 		mod_timer(&device->wd_timer, jiffies);
 	}
+#ifdef CONFIG_PM
+	g_sus_wd_timeout = 0;
+#endif
 	INFO("heci driver initialization successful.\n");
 	return ESUCCESS;
 
@@ -618,6 +629,7 @@
 	spin_unlock_bh(&device->device_lock);
 	spin_lock(&file_extension->file_lock);
 	file_extension->state = HECI_FILE_INITIALIZING;
+	file_extension->sm_state = 0;
 
 	file->private_data = file_extension;
 	spin_unlock(&file_extension->file_lock);
@@ -761,19 +773,26 @@
 	if (!file_extension)
 		return -ENODEV;
 
-	/* Do not allow to read watchdog client */
-	for (i = 0; i < device->num_heci_me_clients; i++) {
-		if (0 == memcmp(&heci_wd_guid, &device->me_clients[i].properteis.protocol_name, sizeof(struct guid))) {
-			if (file_extension->me_client_id == device->me_clients[i].client_id)
-				return -EBADF;
-		}
+	spin_lock(&file_extension->file_lock);
+	if((file_extension->sm_state & HECI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
+			spin_unlock(&file_extension->file_lock);
+			/* Do not allow to read watchdog client */
+ 			for (i = 0; i < device->num_heci_me_clients; i++) {
+				if (0 == memcmp(&heci_wd_guid, &device->me_clients[i].properteis.protocol_name, sizeof(struct guid))) {
+					if (file_extension->me_client_id == device->me_clients[i].client_id)
+						return -EBADF;
+				}
+			}
+	} else {
+		file_extension->sm_state &= ~HECI_WD_STATE_INDEPENDENCE_MSG_SENT;
+		spin_unlock(&file_extension->file_lock);
 	}
 	if (file_extension == &device->legacy_file_extension) {
 		return_status = pthi_read(device, if_num, file, ubuf, length, offset);
 		goto out;
 	}
 
-	if (file_extension->read_cb && file_extension->read_cb->information < *offset) {
+	if (file_extension->read_cb && file_extension->read_cb->information > *offset) {
 		kernel_priv_cb = file_extension->read_cb;
 		goto copy_buffer;
 	}
@@ -967,6 +986,16 @@
 		return_status = -EFAULT;
 		goto fail;
 	}
+	
+	spin_lock(&file_extension->file_lock);
+	file_extension->sm_state = 0;
+	if (length == 4 &&
+		((memcmp(heci_wd_state_independence_msg[0], ubuf, 4) == 0) ||
+		 (memcmp(heci_wd_state_independence_msg[1], ubuf, 4) == 0))) {
+		file_extension->sm_state |= HECI_WD_STATE_INDEPENDENCE_MSG_SENT;
+   }
+	spin_unlock(&file_extension->file_lock);
+
 	INIT_LIST_HEAD(&priv_write_cb->cb_list);
 	if (file_extension == &device->legacy_file_extension) {
 		priv_write_cb->response_buffer.data =
@@ -1305,6 +1334,110 @@
 	return mask;
 }
 
+#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;
+
+	//Stop watchdog if exists
+	del_timer_sync(&device->wd_timer);
+	if (device->wd_file_extension.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 = TRUE;
+			if (device->host_buffer_is_empty &&
+				flow_control_credentials(device, &device->wd_file_extension)) {
+					device->host_buffer_is_empty = FALSE;
+			
+					if (!heci_send_wd(device))
+						DBG("Send stop WD  failed\n");
+			        else
+						flow_control_reduce(device, &device->wd_file_extension);
+					device->wd_pending = FALSE;
+			} else {
+				device->wd_pending = TRUE;
+			}
+			spin_unlock_bh(&device->device_lock);
+			device->wd_stoped = FALSE;
+
+			err =
+				wait_event_interruptible_timeout(device->wait_stop_wd,
+										(TRUE == 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 || 
+			device->heci_state == HECI_RECOVERING_FROM_RESET) {
+		device->heci_state = HECI_POWER_DOWN;
+		heci_reset(device, FALSE);
+	}
+	spin_unlock_bh(&device->device_lock);
+
+	pci_save_state(pdev);
+
+
+	pci_disable_device(pdev);
+	free_irq(pdev->irq, device);
+
+	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;
+
+	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;
+	err = request_irq(device->irq, heci_isr_interrupt, IRQF_SHARED,
+			heci_driver_name, device);
+	if (err) {
+		ERR("Request_irq failure. irq = %d \n", device->irq);
+		return err;
+	}
+
+	spin_lock_bh(&device->device_lock);
+	device->heci_state = HECI_POWER_UP;
+	heci_reset(device, TRUE);	
+	spin_unlock_bh(&device->device_lock);
+
+	//Start watchdog if stopped in suspend
+	if (g_sus_wd_timeout != 0) {
+		device->wd_timeout = g_sus_wd_timeout;
+
+		memcpy(device->wd_data, start_wd_params, HECI_WD_PARAMS_SIZE);
+		memcpy(device->wd_data + HECI_WD_PARAMS_SIZE, &device->wd_timeout, 
+				sizeof(__u16));
+		device->wd_due_counter = 1;
+
+		if (device->wd_timeout)
+			mod_timer(&device->wd_timer, jiffies);
+		g_sus_wd_timeout = 0;
+	}
+	return err;
+}
+#endif
 MODULE_AUTHOR("Intel Corporation"); /* FIXME: Add email address here */
 MODULE_DESCRIPTION("Intel(R) AMT Management Interface");
 MODULE_LICENSE("Dual BSD/GPL");
diff -Nur HECI-3.1.0.31/src/version.h HECI-3.2.0.24/src/version.h
--- HECI-3.1.0.31/src/version.h	2007-08-20 10:07:53.000000000 -0400
+++ HECI-3.2.0.24/src/version.h	2008-01-24 07:04:42.000000000 -0500
@@ -42,9 +42,9 @@
 #define HECI_VERSION_H
 
 #define MAJOR_VERSION              3
-#define MINOR_VERSION              1
+#define MINOR_VERSION              2
 #define QUICK_FIX_NUMBER        0
-#define VER_BUILD               31
+#define VER_BUILD               24
 
 #define str(s) name(s)
 #define name(s) #s