Commit 64578a3de723d502621860f9d4d28f34d001b066

Authored by Tejun Heo
Committed by Jeff Garzik
1 parent e5fa24dfdb

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>

Showing 4 changed files with 171 additions and 5 deletions Side-by-side Diff

drivers/ata/libata-acpi.c
... ... @@ -101,6 +101,108 @@
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 + */
  116 +static 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 + */
  173 +static 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 206 * ata_dev_get_GTF - get the drive bootup default taskfile settings
105 207 * @dev: target ATA device
106 208 * @gtf: output parameter for buffer containing _GTF taskfile arrays
... ... @@ -355,6 +457,46 @@
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 + */
  474 +int 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 500 * ata_acpi_on_resume - ATA ACPI hook called on resume
359 501 * @ap: target ATA port
360 502 *
... ... @@ -368,6 +510,13 @@
368 510 {
369 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 520 /* schedule _GTF */
372 521 for (i = 0; i < ATA_MAX_DEVICES; i++)
373 522 ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING;
... ... @@ -393,10 +542,6 @@
393 542 struct ata_eh_context *ehc = &ap->eh_context;
394 543 int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
395 544 int rc;
396   -
397   - /* XXX: _STM isn't implemented yet, skip if IDE for now */
398   - if (!acpi_sata)
399   - return 0;
400 545  
401 546 if (!dev->acpi_handle)
402 547 return 0;
drivers/ata/libata-eh.c
... ... @@ -2154,19 +2154,25 @@
2154 2154  
2155 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 2162 /* suspend */
2158 2163 ata_eh_freeze_port(ap);
2159 2164  
2160 2165 if (ap->ops->port_suspend)
2161 2166 rc = ap->ops->port_suspend(ap, ap->pm_mesg);
2162 2167  
  2168 + out:
2163 2169 /* report result */
2164 2170 spin_lock_irqsave(ap->lock, flags);
2165 2171  
2166 2172 ap->pflags &= ~ATA_PFLAG_PM_PENDING;
2167 2173 if (rc == 0)
2168 2174 ap->pflags |= ATA_PFLAG_SUSPENDED;
2169   - else
  2175 + else if (ap->pflags & ATA_PFLAG_FROZEN)
2170 2176 ata_port_schedule_eh(ap);
2171 2177  
2172 2178 if (ap->pm_result) {
drivers/ata/libata.h
... ... @@ -99,10 +99,12 @@
99 99 /* libata-acpi.c */
100 100 #ifdef CONFIG_ATA_ACPI
101 101 extern void ata_acpi_associate(struct ata_host *host);
  102 +extern int ata_acpi_on_suspend(struct ata_port *ap);
102 103 extern void ata_acpi_on_resume(struct ata_port *ap);
103 104 extern int ata_acpi_on_devcfg(struct ata_device *adev);
104 105 #else
105 106 static inline void ata_acpi_associate(struct ata_host *host) { }
  107 +static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
106 108 static inline void ata_acpi_on_resume(struct ata_port *ap) { }
107 109 static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
108 110 #endif
include/linux/libata.h
... ... @@ -198,6 +198,7 @@
198 198 ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
199 199 ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */
200 200 ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */
  201 + ATA_PFLAG_GTM_VALID = (1 << 19), /* acpi_gtm data valid */
201 202  
202 203 /* struct ata_queued_cmd flags */
203 204 ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */
... ... @@ -493,6 +494,17 @@
493 494 unsigned int did_probe_mask;
494 495 };
495 496  
  497 +struct ata_acpi_drive
  498 +{
  499 + u32 pio;
  500 + u32 dma;
  501 +} __packed;
  502 +
  503 +struct ata_acpi_gtm {
  504 + struct ata_acpi_drive drive[2];
  505 + u32 flags;
  506 +} __packed;
  507 +
496 508 struct ata_port {
497 509 struct Scsi_Host *scsi_host; /* our co-allocated scsi host */
498 510 const struct ata_port_operations *ops;
... ... @@ -555,6 +567,7 @@
555 567  
556 568 #ifdef CONFIG_ATA_ACPI
557 569 acpi_handle acpi_handle;
  570 + struct ata_acpi_gtm acpi_gtm;
558 571 #endif
559 572 u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
560 573 };