public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
* IDE _GTM/_STM support
@ 2005-05-22 22:35 Matthew Garrett
  2005-05-22 22:50 ` Alan Cox
  0 siblings, 1 reply; 4+ messages in thread
From: Matthew Garrett @ 2005-05-22 22:35 UTC (permalink / raw)
  To: Shaohua Li; +Cc: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

[-- Attachment #1: Type: text/plain, Size: 760 bytes --]

Hi,

Here's a lightly modified version of a patch Shaohua sent me. It does
the following:

* Calls _GTM on suspend
* Passes that information to _STM on resume
* Calls _GTF, but does *not* do anything with that information

With _GTM and _STM support, my HP nc6220 survives a suspend/resume
cycle. If I uncomment the taskfile call in the _GTF routine, the machine
freezes when it tries to perform the first taskfile write. I'm assuming
that an IDE guru needs to take a closer look at what's going on there
(it freezes at wait_for_completion in ide_do_drive_cmd).

Anyway, even without _GTF support, it looks like this patch fixes S3 on
at least some hardware. Patch is against 2.6.12-rc4-mm2.
-- 
Matthew Garrett | mjg59-1xO5oi07KQx4cg9Nei1l7Q@public.gmane.org

[-- Attachment #2: ide.diff --]
[-- Type: text/x-patch, Size: 7479 bytes --]

diff -ur linux-source-2.6.12-2.6.11.92.pristine/drivers/ide/ide.c linux-source-2.6.12-2.6.11.92/drivers/ide/ide.c
--- linux-source-2.6.12-2.6.11.92.pristine/drivers/ide/ide.c	2005-05-22 22:52:40.000000000 +0100
+++ linux-source-2.6.12-2.6.11.92/drivers/ide/ide.c	2005-05-22 22:55:23.000000000 +0100
@@ -1215,6 +1215,237 @@
 
 EXPORT_SYMBOL(system_bus_clock);
 
+#if 1
+#include <linux/acpi.h>
+#define DBG(x...) printk(x)
+static int ide_acpi_find_device(struct device *dev, acpi_handle *handle)
+{
+	int i, tmp;
+	acpi_integer addr;
+
+	if (sscanf(dev->bus_id, "%u.%u", &tmp, &i) != 2)
+		return -ENODEV;
+
+	addr = i;
+	*handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
+	if (!*handle)
+		return -ENODEV;
+	return 0;
+}
+
+/* This assumes the ide controller is a PCI device */
+static int ide_acpi_find_channel(struct device *dev, acpi_handle *handle)
+{
+	int num;
+	int channel;
+	acpi_integer addr;
+
+	num = sscanf(dev->bus_id, "ide%x", &channel);
+
+	if (num != 1 || !dev->parent)
+		return -ENODEV;
+	addr = channel;
+	*handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
+	if (!*handle)
+		return -ENODEV;
+	return 0;
+}
+
+static struct acpi_bus_type ide_acpi_bus = {
+	.bus = &ide_bus_type,
+	.find_device = ide_acpi_find_device,
+	.find_bridge = ide_acpi_find_channel,
+};
+
+static int __init ide_acpi_init(void)
+{
+	return register_acpi_bus_type(&ide_acpi_bus);
+}
+
+#define MAX_DEVICES 10
+#define GTM_LEN (sizeof(u32) * 5)
+static struct acpi_ide_stat {
+	acpi_handle handle; /* channel device's handle */
+	u32	gtm[GTM_LEN/sizeof(u32)]; /* info from _GTM */
+	struct hd_driveid id_buff[2];
+	int channel_handled;
+} device_state[MAX_DEVICES];
+
+static struct acpi_ide_stat *ide_get_acpi_state(acpi_handle handle)
+{
+	int i;
+	for (i = 0; i < MAX_DEVICES; i ++)
+		if (device_state[i].handle == handle)
+			break;
+	if (i < MAX_DEVICES)
+		return &device_state[i];
+	for (i = 0; i < MAX_DEVICES; i ++)
+		if (device_state[i].handle == NULL)
+			break;
+	if (i >= MAX_DEVICES)
+		return NULL;
+
+	memset(&device_state[i], 0, sizeof(struct acpi_ide_stat));
+	return &device_state[i];
+}
+
+int acpi_ide_suspend(struct device *dev)
+{
+	acpi_handle handle, parent_handle;
+	struct acpi_ide_stat *stat;
+	acpi_status	status;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	union acpi_object *package;
+	ide_drive_t *drive = dev->driver_data;
+	int drive_id = 0;
+
+	handle = DEVICE_ACPI_HANDLE(dev);
+	if (!handle) {
+		DBG("IDE device ACPI handler is NULL\n");
+		return -ENODEV;
+	}
+	if (ACPI_FAILURE(acpi_get_parent(handle, &parent_handle))) {
+		printk(KERN_ERR "ACPI get parent handler error\n");
+		return -ENODEV;
+	}
+	stat = ide_get_acpi_state(parent_handle);
+	if (stat == NULL)
+		return -ENODEV;
+	if (stat->channel_handled) {
+		drive_id = 1;
+		goto id;
+	}
+
+	status = acpi_evaluate_object(parent_handle, "_GTM", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR "Error evaluating _GTM\n");
+		return -ENODEV;
+	}
+	package = (union acpi_object *) buffer.pointer;
+	if (package->buffer.length != GTM_LEN) {
+		printk(KERN_ERR "Buffer length returned by _GTM is wrong\n");
+		acpi_os_free(buffer.pointer);
+		return -ENODEV;
+	}
+	memcpy(stat->gtm, package->buffer.pointer, GTM_LEN);
+	stat->handle = parent_handle;
+	stat->channel_handled = 1;
+	acpi_os_free(buffer.pointer);
+id:
+	taskfile_lib_get_identify(drive, &stat->id_buff[drive_id]);
+	DBG("GTM info %x,%x,%x,%x,%x\n", stat->gtm[0],
+		stat->gtm[1], stat->gtm[2],
+		stat->gtm[3], stat->gtm[4]);
+	return 0;
+}
+
+static int acpi_ide_stm(struct acpi_ide_stat *stat)
+{
+	struct acpi_object_list input;
+	union acpi_object params[3];
+	acpi_status status;
+
+	input.count = 3;
+	input.pointer = params;
+	params[0].type = ACPI_TYPE_BUFFER;
+	params[0].buffer.length = sizeof(stat->gtm);
+	params[0].buffer.pointer = (char*)stat->gtm;
+
+	params[1].type = ACPI_TYPE_BUFFER;
+	params[1].buffer.length = sizeof(stat->id_buff[0]);
+	params[1].buffer.pointer = (char *)&stat->id_buff[0];
+
+	params[2].type = ACPI_TYPE_BUFFER;
+	params[2].buffer.length = sizeof(stat->id_buff[1]);
+	params[2].buffer.pointer = (char *)&stat->id_buff[1];
+
+	status = acpi_evaluate_object(stat->handle, "_STM", &input, NULL);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR "Evaluating _STM error\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int acpi_ide_gtf(acpi_handle handle, ide_drive_t *drive)
+{
+	struct acpi_buffer	output = {ACPI_ALLOCATE_BUFFER, NULL};
+	ide_task_t	args;
+	int index = 0;
+	unsigned char *data;
+	union acpi_object	*package = NULL;
+	acpi_status status;
+
+	status = acpi_evaluate_object(handle, "_GTF", NULL, &output);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR "evaluate _GTF error\n");
+		return -ENODEV;
+	}
+	package = (union acpi_object *) output.pointer;
+	if (package->type != ACPI_TYPE_BUFFER
+		|| (package->buffer.length % 7) != 0) {
+		acpi_os_free(output.pointer);
+		printk(KERN_ERR "_GTF returned value is wrong\n");
+		return -ENODEV;
+	}
+	printk("start GTF\n");
+
+	data = package->buffer.pointer;
+	while (index < package->buffer.length) {
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_ERROR_OFFSET] = data[index];
+		args.tfRegister[IDE_NSECTOR_OFFSET] = data[index + 1];
+		args.tfRegister[IDE_SECTOR_OFFSET] = data[index + 2];
+		args.tfRegister[IDE_LCYL_OFFSET] = data[index + 3];
+		args.tfRegister[IDE_HCYL_OFFSET] = data[index + 4];
+		args.tfRegister[IDE_SELECT_OFFSET] = data[index + 5];
+		args.tfRegister[IDE_STATUS_OFFSET] = data[index + 6];
+		args.command_type = IDE_DRIVE_TASK_NO_DATA;
+		args.handler = &task_no_data_intr;
+		printk("data %x,%x,%x,%x,%x,%x,%x\n",
+			data[index], data[index+1], data[index+2],
+			data[index+3],data[index+4],data[index+5],
+			data[index+6]);
+		/* submit command request */
+//		printk("return value %d\n", ide_raw_taskfile(drive, &args, NULL));
+		index += 7;
+	}
+	acpi_os_free(output.pointer);
+	return 0;
+}
+
+int acpi_ide_resume(struct device *dev)
+{
+	acpi_handle handle, parent_handle;
+	struct acpi_ide_stat *stat;
+	ide_drive_t *drive = dev->driver_data;
+
+	handle = DEVICE_ACPI_HANDLE(dev);
+	if (!handle) {
+		DBG("IDE device ACPI handler is NULL\n");
+		return -ENODEV;
+	}
+	if (ACPI_FAILURE(acpi_get_parent(handle, &parent_handle))) {
+		printk(KERN_ERR "ACPI get parent handler error\n");
+		return -ENODEV;
+	}
+	stat = ide_get_acpi_state(parent_handle);
+	if (stat == NULL || stat->handle != parent_handle)
+		return -ENODEV;
+
+	if (stat->channel_handled == 0) {
+		stat->handle = NULL;
+		goto gtf;
+	}
+DBG("Start STM\n");
+	if (acpi_ide_stm(stat))
+		return -ENODEV;
+	stat->channel_handled = 0;
+gtf:
+	return acpi_ide_gtf(handle, drive);
+}
+#endif
+
 static int generic_ide_suspend(struct device *dev, pm_message_t state)
 {
 	ide_drive_t *drive = dev->driver_data;
@@ -1230,7 +1461,7 @@
 	rq.pm = &rqpm;
 	rqpm.pm_step = ide_pm_state_start_suspend;
 	rqpm.pm_state = state;
-
+acpi_ide_suspend(dev);
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
@@ -1240,7 +1471,7 @@
 	struct request rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
-
+	acpi_ide_resume(dev);
 	memset(&rq, 0, sizeof(rq));
 	memset(&rqpm, 0, sizeof(rqpm));
 	memset(&args, 0, sizeof(args));
@@ -1923,6 +2154,7 @@
 	devfs_mk_dir("ide");
 	system_bus_speed = ide_system_bus_speed();
 
+ide_acpi_init();
 	bus_register(&ide_bus_type);
 
 	init_ide_data();
Only in linux-source-2.6.12-2.6.11.92/drivers/ide/: ide.c.orig

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-05-23 11:08 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-05-22 22:35 IDE _GTM/_STM support Matthew Garrett
2005-05-22 22:50 ` Alan Cox
     [not found]   ` <1116802237.5730.29.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2005-05-23  2:07     ` Shaohua Li
     [not found]       ` <1116814023.3852.6.camel-ECwVeV2eNyQD0+JXs3kMbRL4W9x8LtSr@public.gmane.org>
2005-05-23 11:08         ` Alan Cox

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox