From: Matthew Garrett <mjg59@srcf.ucam.org>
To: linux-ide@vger.kernel.org, linux-acpi@vger.kernel.org
Cc: kristen.c.accardi@intel.com
Subject: [PATCH] Add _GTM and _STM support to libata
Date: Mon, 26 Mar 2007 04:22:23 +0100 [thread overview]
Message-ID: <20070326032222.GA13113@srcf.ucam.org> (raw)
I've ported the drivers/ide code for handling _GTM and _STM to libata.
I'm not utterly convinced that I'm doing the calls in the right place -
should they be attached to the scsi code rather than the ata host code?
Anyway, this fixes suspend/resume on nc6220, which is what I was aiming
for...
Signed-off-by: Matthew Garrett <mjg59@srcf.ucam.org>
---
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index c428a56..0e542ea 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -34,6 +34,19 @@ struct taskfile_array {
u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
};
+struct GTM_buffer {
+ u32 PIO_speed0;
+ u32 DMA_speed0;
+ u32 PIO_speed1;
+ u32 DMA_speed1;
+ u32 GTM_flags;
+};
+
+struct ata_acpi_port_link {
+ acpi_handle obj_handle;
+ struct GTM_buffer gtm;
+};
+
/*
* Helper - belongs in the PCI layer somewhere eventually
*/
@@ -706,4 +719,125 @@ out:
return 0;
}
+/**
+ * ata_acpi_get_timings - get the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _GTM ACPI method for the target channel.
+ *
+ */
+void ata_acpi_get_timings(struct ata_port *ap)
+{
+ acpi_status status;
+ int err;
+ acpi_handle dev_handle = NULL;
+ acpi_integer pcidevfn = 0;
+ struct device *dev = ap->host->dev;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+
+ if (noacpi)
+ return;
+
+ if (ap->cbl == ATA_CBL_SATA)
+ return;
+ err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn);
+
+ if (err < 0)
+ return;
+
+ ap->port_handle = acpi_get_child(dev_handle, ap->port_no);
+
+ /* Setting up output buffer for _GTM */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTM has no input parameters */
+ status = acpi_evaluate_object(ap->port_handle, "_GTM",
+ NULL, &output);
+
+ if (ACPI_FAILURE(status))
+ return;
+
+ if (!output.length || !output.pointer) {
+ kfree(output.pointer);
+ return;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ kfree(output.pointer);
+ return;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length != sizeof(struct GTM_buffer)) {
+ kfree(output.pointer);
+ printk(KERN_ERR
+ "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or \
+"
+ "addr (0x%p)\n",
+ __FUNCTION__, out_obj->buffer.length,
+ sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+ return;
+ }
+
+ if (!ap->acpidata) {
+ ap->acpidata = kzalloc(sizeof(struct ata_acpi_port_link), GFP_KERNEL);
+ if (!ap->acpidata)
+ return;
+ }
+
+ memcpy(&ap->acpidata->gtm, out_obj->buffer.pointer,
+ sizeof(struct GTM_buffer));
+
+ kfree(output.pointer);
+}
+EXPORT_SYMBOL_GPL(ata_acpi_get_timings);
+
+/**
+ * ata_acpi_push_timings - set the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _STM ACPI method for the target channel.
+ *
+ * _STM requires Identify Drive data, which has to passed as an argument.
+ * Unfortunately hd_driveid is a mangled version which we can't readily
+ * use; hence we'll get the information afresh.
+ */
+void ata_acpi_push_timings(struct ata_port *ap)
+{
+ acpi_status status;
+ struct acpi_object_list input;
+ union acpi_object in_params[3];
+
+ if (noacpi)
+ return;
+
+ if (!ap->acpidata)
+ return;
+
+ /* Give the GTM buffer + drive Identify data to the channel via the
+ * _STM method: */
+ /* setup input parameters buffer for _STM */
+ input.count = 3;
+ input.pointer = in_params;
+ in_params[0].type = ACPI_TYPE_BUFFER;
+ in_params[0].buffer.length = sizeof(struct GTM_buffer);
+ in_params[0].buffer.pointer = (u8 *)&ap->acpidata->gtm;
+ in_params[1].type = ACPI_TYPE_BUFFER;
+ in_params[1].buffer.length = sizeof(ap->device[0].id[0]) * ATA_ID_WORDS;
+ in_params[1].buffer.pointer = (u8 *)&ap->device[0].id;
+ in_params[2].type = ACPI_TYPE_BUFFER;
+ in_params[2].buffer.length = sizeof(ap->device[1].id[0]) * ATA_ID_WORDS;
+ in_params[2].buffer.pointer = (u8 *)&ap->device[1].id;
+ /* Output buffer: _STM has no output */
+
+ status = acpi_evaluate_object(ap->port_handle, "_STM",
+ &input, NULL);
+
+ if (ACPI_FAILURE(status))
+ return;
+}
+EXPORT_SYMBOL_GPL(ata_acpi_push_timings);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index bf327d4..df38fc3 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5444,6 +5444,7 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
goto fail;
}
}
+ ata_acpi_get_timings(ap);
}
host->dev->power.power_state = mesg;
@@ -5467,6 +5468,11 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
*/
void ata_host_resume(struct ata_host *host)
{
+ int i;
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ ata_acpi_push_timings(ap);
+ }
ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET,
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
host->dev->power.power_state = PMSG_ON;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index c426714..277982c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -101,6 +101,8 @@ extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
#ifdef CONFIG_SATA_ACPI
extern int ata_acpi_exec_tfs(struct ata_port *ap);
extern int ata_acpi_push_id(struct ata_port *ap, unsigned int ix);
+extern void ata_acpi_get_timings(struct ata_port *ap);
+extern void ata_acpi_push_timings(struct ata_port *ap);
#else
static inline int ata_acpi_exec_tfs(struct ata_port *ap)
{
@@ -110,6 +112,14 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
{
return 0;
}
+static inline void ata_acpi_get_timings(struct ata_port *ap)
+{
+ return;
+}
+extern void ata_acpi_push_timings(struct ata_port *ap)
+{
+ return;
+}
#endif
/* libata-scsi.c */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index e3f32f3..b141863 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -340,6 +340,9 @@ struct scsi_device;
struct ata_port_operations;
struct ata_port;
struct ata_queued_cmd;
+#ifdef CONFIG_SATA_ACPI
+struct ata_acpi_port_link;
+#endif
/* typedefs */
typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
@@ -590,6 +593,11 @@ struct ata_port {
void *private_data;
u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
+#ifdef CONFIG_SATA_ACPI
+ /* ACPI objects info */
+ acpi_handle port_handle;
+ struct ata_acpi_port_link *acpidata;
+#endif
};
struct ata_port_operations {
--
Matthew Garrett | mjg59@srcf.ucam.org
next reply other threads:[~2007-03-26 3:22 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-26 3:22 Matthew Garrett [this message]
2007-03-26 3:39 ` [PATCH] Add _GTM and _STM support to libata Matthew Garrett
2007-03-26 10:58 ` Alan Cox
2007-03-26 20:15 ` Matthew Garrett
2007-03-26 21:40 ` Alan Cox
2007-03-26 21:48 ` Matthew Garrett
2007-03-26 23:39 ` Alan Cox
2007-03-26 22:44 ` Matthew Garrett
2007-03-26 11:02 ` Alan Cox
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070326032222.GA13113@srcf.ucam.org \
--to=mjg59@srcf.ucam.org \
--cc=kristen.c.accardi@intel.com \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-ide@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.