aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libata-acpi.c')
-rw-r--r--drivers/ata/libata-acpi.c153
1 files changed, 149 insertions, 4 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