diff options
author | Tejun Heo <htejun@gmail.com> | 2007-12-15 01:05:02 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-12-17 20:33:14 -0500 |
commit | c05e6ff035c1b25d17364a685432b33937d3dc23 (patch) | |
tree | 08c9171d024b6659b29a4f9f7d95318430b75b6a | |
parent | 562f0c2d771ee7be6b37fe015f94a929f8056120 (diff) |
libata-acpi: implement and use ata_acpi_init_gtm()
_GTM fetches currently configured transfer mode while _STM configures
controller according to _GTM parameter and prepares transfer mode
configuration TFs for _GTF. In many cases _GTM and _STM
implementations are quite brittle and can't cope with configuration
changed by libata.
libata does not depend on ATA ACPI to configure devices. The only
reason libata performs _GTM and _STM are to make _GTF evaluation
succeed and libata also doesn't care about how _GTF TFs configure
transfer mode. It overrides that configuration anyway, so from
libata's POV, it doesn't matter what value is feeded to _STM as long
as evaluation succeeds for _STM and following _GTF.
This patch adds dev->__acpi_init_gtm and store initial _GTM values on
host initialization before modified by reset and mode configuration.
If the field is valid, ata_acpi_init_gtm() returns pointer to the
saved _GTM structure; otherwise, NULL.
This saved value is used for _STM during resume and peek at
BIOS/firmware programmed initial timing for later use. The accessor
is there to make building w/o ACPI easy as dev->__acpi_init doesn't
exist if ACPI is not enabled.
On driver detach, the initial BIOS configuration is restored by
executing _STM with the initial _GTM values such that the next driver
can also use the initial BIOS configured values.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/libata-acpi.c | 62 | ||||
-rw-r--r-- | include/linux/libata.h | 14 |
2 files changed, 39 insertions, 37 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 9e5fc5d75b2e..b3aeca368774 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -94,6 +94,9 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) | |||
94 | 94 | ||
95 | dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); | 95 | dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); |
96 | } | 96 | } |
97 | |||
98 | if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) | ||
99 | ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; | ||
97 | } | 100 | } |
98 | 101 | ||
99 | static void ata_acpi_handle_hotplug(struct ata_port *ap, struct kobject *kobj, | 102 | static void ata_acpi_handle_hotplug(struct ata_port *ap, struct kobject *kobj, |
@@ -199,7 +202,18 @@ void ata_acpi_associate(struct ata_host *host) | |||
199 | */ | 202 | */ |
200 | void ata_acpi_dissociate(struct ata_host *host) | 203 | void ata_acpi_dissociate(struct ata_host *host) |
201 | { | 204 | { |
202 | /* nada */ | 205 | int i; |
206 | |||
207 | /* Restore initial _GTM values so that driver which attaches | ||
208 | * afterward can use them too. | ||
209 | */ | ||
210 | for (i = 0; i < host->n_ports; i++) { | ||
211 | struct ata_port *ap = host->ports[i]; | ||
212 | const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); | ||
213 | |||
214 | if (ap->acpi_handle && gtm) | ||
215 | ata_acpi_stm(ap, gtm); | ||
216 | } | ||
203 | } | 217 | } |
204 | 218 | ||
205 | /** | 219 | /** |
@@ -409,22 +423,21 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, | |||
409 | 423 | ||
410 | int ata_acpi_cbl_80wire(struct ata_port *ap) | 424 | int ata_acpi_cbl_80wire(struct ata_port *ap) |
411 | { | 425 | { |
412 | struct ata_acpi_gtm gtm; | 426 | const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); |
413 | int valid = 0; | 427 | int valid = 0; |
414 | 428 | ||
415 | /* No _GTM data, no information */ | 429 | if (!gtm) |
416 | if (ata_acpi_gtm(ap, >m) < 0) | ||
417 | return 0; | 430 | return 0; |
418 | 431 | ||
419 | /* Split timing, DMA enabled */ | 432 | /* Split timing, DMA enabled */ |
420 | if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55) | 433 | if ((gtm->flags & 0x11) == 0x11 && gtm->drive[0].dma < 55) |
421 | valid |= 1; | 434 | valid |= 1; |
422 | if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55) | 435 | if ((gtm->flags & 0x14) == 0x14 && gtm->drive[1].dma < 55) |
423 | valid |= 2; | 436 | valid |= 2; |
424 | /* Shared timing, DMA enabled */ | 437 | /* Shared timing, DMA enabled */ |
425 | if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55) | 438 | if ((gtm->flags & 0x11) == 0x01 && gtm->drive[0].dma < 55) |
426 | valid |= 1; | 439 | valid |= 1; |
427 | if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55) | 440 | if ((gtm->flags & 0x14) == 0x04 && gtm->drive[0].dma < 55) |
428 | valid |= 2; | 441 | valid |= 2; |
429 | 442 | ||
430 | /* Drive check */ | 443 | /* Drive check */ |
@@ -612,27 +625,8 @@ static int ata_acpi_push_id(struct ata_device *dev) | |||
612 | */ | 625 | */ |
613 | int ata_acpi_on_suspend(struct ata_port *ap) | 626 | int ata_acpi_on_suspend(struct ata_port *ap) |
614 | { | 627 | { |
615 | unsigned long flags; | 628 | /* nada */ |
616 | int rc; | 629 | return 0; |
617 | |||
618 | /* proceed iff per-port acpi_handle is valid */ | ||
619 | if (!ap->acpi_handle) | ||
620 | return 0; | ||
621 | BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); | ||
622 | |||
623 | /* store timing parameters */ | ||
624 | rc = ata_acpi_gtm(ap, &ap->acpi_gtm); | ||
625 | |||
626 | spin_lock_irqsave(ap->lock, flags); | ||
627 | if (rc == 0) | ||
628 | ap->pflags |= ATA_PFLAG_GTM_VALID; | ||
629 | else | ||
630 | ap->pflags &= ~ATA_PFLAG_GTM_VALID; | ||
631 | spin_unlock_irqrestore(ap->lock, flags); | ||
632 | |||
633 | if (rc == -ENOENT) | ||
634 | rc = 0; | ||
635 | return rc; | ||
636 | } | 630 | } |
637 | 631 | ||
638 | /** | 632 | /** |
@@ -647,14 +641,12 @@ int ata_acpi_on_suspend(struct ata_port *ap) | |||
647 | */ | 641 | */ |
648 | void ata_acpi_on_resume(struct ata_port *ap) | 642 | void ata_acpi_on_resume(struct ata_port *ap) |
649 | { | 643 | { |
644 | const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); | ||
650 | struct ata_device *dev; | 645 | struct ata_device *dev; |
651 | 646 | ||
652 | if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) { | 647 | /* restore timing parameters */ |
653 | BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); | 648 | if (ap->acpi_handle && gtm) |
654 | 649 | ata_acpi_stm(ap, gtm); | |
655 | /* restore timing parameters */ | ||
656 | ata_acpi_stm(ap, &ap->acpi_gtm); | ||
657 | } | ||
658 | 650 | ||
659 | /* schedule _GTF */ | 651 | /* schedule _GTF */ |
660 | ata_link_for_each_dev(dev, &ap->link) | 652 | ata_link_for_each_dev(dev, &ap->link) |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 3784af395576..ba84d8a37545 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -211,7 +211,7 @@ enum { | |||
211 | 211 | ||
212 | ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */ | 212 | ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */ |
213 | ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */ | 213 | ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */ |
214 | ATA_PFLAG_GTM_VALID = (1 << 19), /* acpi_gtm data valid */ | 214 | ATA_PFLAG_INIT_GTM_VALID = (1 << 19), /* initial gtm data valid */ |
215 | 215 | ||
216 | /* struct ata_queued_cmd flags */ | 216 | /* struct ata_queued_cmd flags */ |
217 | ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ | 217 | ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ |
@@ -653,7 +653,7 @@ struct ata_port { | |||
653 | 653 | ||
654 | #ifdef CONFIG_ATA_ACPI | 654 | #ifdef CONFIG_ATA_ACPI |
655 | acpi_handle acpi_handle; | 655 | acpi_handle acpi_handle; |
656 | struct ata_acpi_gtm acpi_gtm; | 656 | struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ |
657 | #endif | 657 | #endif |
658 | u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */ | 658 | u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */ |
659 | }; | 659 | }; |
@@ -939,10 +939,20 @@ enum { | |||
939 | 939 | ||
940 | /* libata-acpi.c */ | 940 | /* libata-acpi.c */ |
941 | #ifdef CONFIG_ATA_ACPI | 941 | #ifdef CONFIG_ATA_ACPI |
942 | static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap) | ||
943 | { | ||
944 | if (ap->pflags & ATA_PFLAG_INIT_GTM_VALID) | ||
945 | return &ap->__acpi_init_gtm; | ||
946 | return NULL; | ||
947 | } | ||
942 | extern int ata_acpi_cbl_80wire(struct ata_port *ap); | 948 | extern int ata_acpi_cbl_80wire(struct ata_port *ap); |
943 | int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm); | 949 | int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm); |
944 | int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *stm); | 950 | int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *stm); |
945 | #else | 951 | #else |
952 | static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap) | ||
953 | { | ||
954 | return NULL; | ||
955 | } | ||
946 | static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } | 956 | static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } |
947 | #endif | 957 | #endif |
948 | 958 | ||