aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-05-14 14:28:16 -0400
committerJeff Garzik <jeff@garzik.org>2007-07-09 12:17:32 -0400
commit64578a3de723d502621860f9d4d28f34d001b066 (patch)
tree821e7ad8e8d6c3a0f3224b479ff000e00001a165 /drivers/ata
parente5fa24dfdb522b642dbe9b8b1b692f68dce89835 (diff)
libata-acpi: implement _GTM/_STM support
Implement _GTM/_STM support. acpi_gtm is added to ata_port which stores _GTM parameters over suspend/resume cycle. A new hook ata_acpi_on_suspend() is responsible for storing _GTM parameters during suspend. _STM is executed in ata_acpi_on_resume(). With this change, invoking _GTF is safe on IDE hierarchy and acpi_sata check before _GTF is removed. ata_acpi_gtm() and ata_acpi_stm() implementation is taken from Alan Cox's pata_acpi implementation. ata_acpi_gtm() is fixed such that the result parameter is not shifted by sizeof(union acpi_object). Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-acpi.c153
-rw-r--r--drivers/ata/libata-eh.c8
-rw-r--r--drivers/ata/libata.h2
3 files changed, 158 insertions, 5 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 78db2e67d7c7..c059f78ad944 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -101,6 +101,108 @@ void ata_acpi_associate(struct ata_host *host)
101} 101}
102 102
103/** 103/**
104 * ata_acpi_gtm - execute _GTM
105 * @ap: target ATA port
106 * @gtm: out parameter for _GTM result
107 *
108 * Evaluate _GTM and store the result in @gtm.
109 *
110 * LOCKING:
111 * EH context.
112 *
113 * RETURNS:
114 * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
115 */
116static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
117{
118 struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
119 union acpi_object *out_obj;
120 acpi_status status;
121 int rc = 0;
122
123 status = acpi_evaluate_object(ap->acpi_handle, "_GTM", NULL, &output);
124
125 rc = -ENOENT;
126 if (status == AE_NOT_FOUND)
127 goto out_free;
128
129 rc = -EINVAL;
130 if (ACPI_FAILURE(status)) {
131 ata_port_printk(ap, KERN_ERR,
132 "ACPI get timing mode failed (AE 0x%x)\n",
133 status);
134 goto out_free;
135 }
136
137 out_obj = output.pointer;
138 if (out_obj->type != ACPI_TYPE_BUFFER) {
139 ata_port_printk(ap, KERN_WARNING,
140 "_GTM returned unexpected object type 0x%x\n",
141 out_obj->type);
142
143 goto out_free;
144 }
145
146 if (out_obj->buffer.length != sizeof(struct ata_acpi_gtm)) {
147 ata_port_printk(ap, KERN_ERR,
148 "_GTM returned invalid length %d\n",
149 out_obj->buffer.length);
150 goto out_free;
151 }
152
153 memcpy(gtm, out_obj->buffer.pointer, sizeof(struct ata_acpi_gtm));
154 rc = 0;
155 out_free:
156 kfree(output.pointer);
157 return rc;
158}
159
160/**
161 * ata_acpi_stm - execute _STM
162 * @ap: target ATA port
163 * @stm: timing parameter to _STM
164 *
165 * Evaluate _STM with timing parameter @stm.
166 *
167 * LOCKING:
168 * EH context.
169 *
170 * RETURNS:
171 * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure.
172 */
173static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
174{
175 acpi_status status;
176 struct acpi_object_list input;
177 union acpi_object in_params[3];
178
179 in_params[0].type = ACPI_TYPE_BUFFER;
180 in_params[0].buffer.length = sizeof(struct ata_acpi_gtm);
181 in_params[0].buffer.pointer = (u8 *)stm;
182 /* Buffers for id may need byteswapping ? */
183 in_params[1].type = ACPI_TYPE_BUFFER;
184 in_params[1].buffer.length = 512;
185 in_params[1].buffer.pointer = (u8 *)ap->device[0].id;
186 in_params[2].type = ACPI_TYPE_BUFFER;
187 in_params[2].buffer.length = 512;
188 in_params[2].buffer.pointer = (u8 *)ap->device[1].id;
189
190 input.count = 3;
191 input.pointer = in_params;
192
193 status = acpi_evaluate_object(ap->acpi_handle, "_STM", &input, NULL);
194
195 if (status == AE_NOT_FOUND)
196 return -ENOENT;
197 if (ACPI_FAILURE(status)) {
198 ata_port_printk(ap, KERN_ERR,
199 "ACPI set timing mode failed (status=0x%x)\n", status);
200 return -EINVAL;
201 }
202 return 0;
203}
204
205/**
104 * ata_dev_get_GTF - get the drive bootup default taskfile settings 206 * ata_dev_get_GTF - get the drive bootup default taskfile settings
105 * @dev: target ATA device 207 * @dev: target ATA device
106 * @gtf: output parameter for buffer containing _GTF taskfile arrays 208 * @gtf: output parameter for buffer containing _GTF taskfile arrays
@@ -355,6 +457,46 @@ static int ata_acpi_push_id(struct ata_device *dev)
355} 457}
356 458
357/** 459/**
460 * ata_acpi_on_suspend - ATA ACPI hook called on suspend
461 * @ap: target ATA port
462 *
463 * This function is called when @ap is about to be suspended. All
464 * devices are already put to sleep but the port_suspend() callback
465 * hasn't been executed yet. Error return from this function aborts
466 * suspend.
467 *
468 * LOCKING:
469 * EH context.
470 *
471 * RETURNS:
472 * 0 on success, -errno on failure.
473 */
474int ata_acpi_on_suspend(struct ata_port *ap)
475{
476 unsigned long flags;
477 int rc;
478
479 /* proceed iff per-port acpi_handle is valid */
480 if (!ap->acpi_handle)
481 return 0;
482 BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA);
483
484 /* store timing parameters */
485 rc = ata_acpi_gtm(ap, &ap->acpi_gtm);
486
487 spin_lock_irqsave(ap->lock, flags);
488 if (rc == 0)
489 ap->pflags |= ATA_PFLAG_GTM_VALID;
490 else
491 ap->pflags &= ~ATA_PFLAG_GTM_VALID;
492 spin_unlock_irqrestore(ap->lock, flags);
493
494 if (rc == -ENOENT)
495 rc = 0;
496 return rc;
497}
498
499/**
358 * ata_acpi_on_resume - ATA ACPI hook called on resume 500 * ata_acpi_on_resume - ATA ACPI hook called on resume
359 * @ap: target ATA port 501 * @ap: target ATA port
360 * 502 *
@@ -368,6 +510,13 @@ void ata_acpi_on_resume(struct ata_port *ap)
368{ 510{
369 int i; 511 int i;
370 512
513 if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) {
514 BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA);
515
516 /* restore timing parameters */
517 ata_acpi_stm(ap, &ap->acpi_gtm);
518 }
519
371 /* schedule _GTF */ 520 /* schedule _GTF */
372 for (i = 0; i < ATA_MAX_DEVICES; i++) 521 for (i = 0; i < ATA_MAX_DEVICES; i++)
373 ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING; 522 ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING;
@@ -394,10 +543,6 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
394 int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; 543 int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
395 int rc; 544 int rc;
396 545
397 /* XXX: _STM isn't implemented yet, skip if IDE for now */
398 if (!acpi_sata)
399 return 0;
400
401 if (!dev->acpi_handle) 546 if (!dev->acpi_handle)
402 return 0; 547 return 0;
403 548
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index fed217db82d2..9ee0a8c08d96 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2154,19 +2154,25 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
2154 2154
2155 WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); 2155 WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
2156 2156
2157 /* tell ACPI we're suspending */
2158 rc = ata_acpi_on_suspend(ap);
2159 if (rc)
2160 goto out;
2161
2157 /* suspend */ 2162 /* suspend */
2158 ata_eh_freeze_port(ap); 2163 ata_eh_freeze_port(ap);
2159 2164
2160 if (ap->ops->port_suspend) 2165 if (ap->ops->port_suspend)
2161 rc = ap->ops->port_suspend(ap, ap->pm_mesg); 2166 rc = ap->ops->port_suspend(ap, ap->pm_mesg);
2162 2167
2168 out:
2163 /* report result */ 2169 /* report result */
2164 spin_lock_irqsave(ap->lock, flags); 2170 spin_lock_irqsave(ap->lock, flags);
2165 2171
2166 ap->pflags &= ~ATA_PFLAG_PM_PENDING; 2172 ap->pflags &= ~ATA_PFLAG_PM_PENDING;
2167 if (rc == 0) 2173 if (rc == 0)
2168 ap->pflags |= ATA_PFLAG_SUSPENDED; 2174 ap->pflags |= ATA_PFLAG_SUSPENDED;
2169 else 2175 else if (ap->pflags & ATA_PFLAG_FROZEN)
2170 ata_port_schedule_eh(ap); 2176 ata_port_schedule_eh(ap);
2171 2177
2172 if (ap->pm_result) { 2178 if (ap->pm_result) {
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index bee7cbc4c97c..ba17fc5f2e99 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -99,10 +99,12 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host);
99/* libata-acpi.c */ 99/* libata-acpi.c */
100#ifdef CONFIG_ATA_ACPI 100#ifdef CONFIG_ATA_ACPI
101extern void ata_acpi_associate(struct ata_host *host); 101extern void ata_acpi_associate(struct ata_host *host);
102extern int ata_acpi_on_suspend(struct ata_port *ap);
102extern void ata_acpi_on_resume(struct ata_port *ap); 103extern void ata_acpi_on_resume(struct ata_port *ap);
103extern int ata_acpi_on_devcfg(struct ata_device *adev); 104extern int ata_acpi_on_devcfg(struct ata_device *adev);
104#else 105#else
105static inline void ata_acpi_associate(struct ata_host *host) { } 106static inline void ata_acpi_associate(struct ata_host *host) { }
107static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
106static inline void ata_acpi_on_resume(struct ata_port *ap) { } 108static inline void ata_acpi_on_resume(struct ata_port *ap) { }
107static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; } 109static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
108#endif 110#endif