diff options
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/ata_piix.c | 113 |
1 files changed, 111 insertions, 2 deletions
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index d9fa329fd157..ad070861bb53 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c | |||
@@ -91,6 +91,7 @@ | |||
91 | #include <linux/device.h> | 91 | #include <linux/device.h> |
92 | #include <scsi/scsi_host.h> | 92 | #include <scsi/scsi_host.h> |
93 | #include <linux/libata.h> | 93 | #include <linux/libata.h> |
94 | #include <linux/dmi.h> | ||
94 | 95 | ||
95 | #define DRV_NAME "ata_piix" | 96 | #define DRV_NAME "ata_piix" |
96 | #define DRV_VERSION "2.11" | 97 | #define DRV_VERSION "2.11" |
@@ -140,6 +141,9 @@ enum { | |||
140 | RV = -3, /* reserved */ | 141 | RV = -3, /* reserved */ |
141 | 142 | ||
142 | PIIX_AHCI_DEVICE = 6, | 143 | PIIX_AHCI_DEVICE = 6, |
144 | |||
145 | /* host->flags bits */ | ||
146 | PIIX_HOST_BROKEN_SUSPEND = (1 << 24), | ||
143 | }; | 147 | }; |
144 | 148 | ||
145 | struct piix_map_db { | 149 | struct piix_map_db { |
@@ -159,6 +163,10 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); | |||
159 | static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); | 163 | static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); |
160 | static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev); | 164 | static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev); |
161 | static int ich_pata_cable_detect(struct ata_port *ap); | 165 | static int ich_pata_cable_detect(struct ata_port *ap); |
166 | #ifdef CONFIG_PM | ||
167 | static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); | ||
168 | static int piix_pci_device_resume(struct pci_dev *pdev); | ||
169 | #endif | ||
162 | 170 | ||
163 | static unsigned int in_module_init = 1; | 171 | static unsigned int in_module_init = 1; |
164 | 172 | ||
@@ -255,8 +263,8 @@ static struct pci_driver piix_pci_driver = { | |||
255 | .probe = piix_init_one, | 263 | .probe = piix_init_one, |
256 | .remove = ata_pci_remove_one, | 264 | .remove = ata_pci_remove_one, |
257 | #ifdef CONFIG_PM | 265 | #ifdef CONFIG_PM |
258 | .suspend = ata_pci_device_suspend, | 266 | .suspend = piix_pci_device_suspend, |
259 | .resume = ata_pci_device_resume, | 267 | .resume = piix_pci_device_resume, |
260 | #endif | 268 | #endif |
261 | }; | 269 | }; |
262 | 270 | ||
@@ -881,6 +889,107 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev) | |||
881 | do_pata_set_dmamode(ap, adev, 1); | 889 | do_pata_set_dmamode(ap, adev, 1); |
882 | } | 890 | } |
883 | 891 | ||
892 | #ifdef CONFIG_PM | ||
893 | static struct dmi_system_id piix_broken_suspend_dmi_table[] = { | ||
894 | { | ||
895 | .ident = "TECRA M5", | ||
896 | .matches = { | ||
897 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
898 | DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"), | ||
899 | }, | ||
900 | }, | ||
901 | { | ||
902 | .ident = "Satellite U200", | ||
903 | .matches = { | ||
904 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
905 | DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"), | ||
906 | }, | ||
907 | }, | ||
908 | { | ||
909 | .ident = "Satellite U205", | ||
910 | .matches = { | ||
911 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
912 | DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U205"), | ||
913 | }, | ||
914 | }, | ||
915 | { | ||
916 | .ident = "Portege M500", | ||
917 | .matches = { | ||
918 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
919 | DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"), | ||
920 | }, | ||
921 | }, | ||
922 | { } | ||
923 | }; | ||
924 | |||
925 | static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) | ||
926 | { | ||
927 | struct ata_host *host = dev_get_drvdata(&pdev->dev); | ||
928 | unsigned long flags; | ||
929 | int rc = 0; | ||
930 | |||
931 | rc = ata_host_suspend(host, mesg); | ||
932 | if (rc) | ||
933 | return rc; | ||
934 | |||
935 | /* Some braindamaged ACPI suspend implementations expect the | ||
936 | * controller to be awake on entry; otherwise, it burns cpu | ||
937 | * cycles and power trying to do something to the sleeping | ||
938 | * beauty. | ||
939 | */ | ||
940 | if (dmi_check_system(piix_broken_suspend_dmi_table) && | ||
941 | mesg.event == PM_EVENT_SUSPEND) { | ||
942 | pci_save_state(pdev); | ||
943 | |||
944 | /* mark its power state as "unknown", since we don't | ||
945 | * know if e.g. the BIOS will change its device state | ||
946 | * when we suspend. | ||
947 | */ | ||
948 | if (pdev->current_state == PCI_D0) | ||
949 | pdev->current_state = PCI_UNKNOWN; | ||
950 | |||
951 | /* tell resume that it's waking up from broken suspend */ | ||
952 | spin_lock_irqsave(&host->lock, flags); | ||
953 | host->flags |= PIIX_HOST_BROKEN_SUSPEND; | ||
954 | spin_unlock_irqrestore(&host->lock, flags); | ||
955 | } else | ||
956 | ata_pci_device_do_suspend(pdev, mesg); | ||
957 | |||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | static int piix_pci_device_resume(struct pci_dev *pdev) | ||
962 | { | ||
963 | struct ata_host *host = dev_get_drvdata(&pdev->dev); | ||
964 | unsigned long flags; | ||
965 | int rc; | ||
966 | |||
967 | if (host->flags & PIIX_HOST_BROKEN_SUSPEND) { | ||
968 | spin_lock_irqsave(&host->lock, flags); | ||
969 | host->flags &= ~PIIX_HOST_BROKEN_SUSPEND; | ||
970 | spin_unlock_irqrestore(&host->lock, flags); | ||
971 | |||
972 | pci_set_power_state(pdev, PCI_D0); | ||
973 | pci_restore_state(pdev); | ||
974 | |||
975 | /* PCI device wasn't disabled during suspend. Use | ||
976 | * __pci_reenable_device() to avoid affecting the | ||
977 | * enable count. | ||
978 | */ | ||
979 | rc = __pci_reenable_device(pdev); | ||
980 | if (rc) | ||
981 | dev_printk(KERN_ERR, &pdev->dev, "failed to enable " | ||
982 | "device after resume (%d)\n", rc); | ||
983 | } else | ||
984 | rc = ata_pci_device_do_resume(pdev); | ||
985 | |||
986 | if (rc == 0) | ||
987 | ata_host_resume(host); | ||
988 | |||
989 | return rc; | ||
990 | } | ||
991 | #endif | ||
992 | |||
884 | #define AHCI_PCI_BAR 5 | 993 | #define AHCI_PCI_BAR 5 |
885 | #define AHCI_GLOBAL_CTL 0x04 | 994 | #define AHCI_GLOBAL_CTL 0x04 |
886 | #define AHCI_ENABLE (1 << 31) | 995 | #define AHCI_ENABLE (1 << 31) |