diff options
-rw-r--r-- | drivers/ata/sata_via.c | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 17d31fc009ab..9804054e22a7 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c | |||
@@ -73,7 +73,14 @@ enum { | |||
73 | SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ | 73 | SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ |
74 | }; | 74 | }; |
75 | 75 | ||
76 | struct svia_priv { | ||
77 | bool wd_workaround; | ||
78 | }; | ||
79 | |||
76 | static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); | 80 | static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); |
81 | #ifdef CONFIG_PM_SLEEP | ||
82 | static int svia_pci_device_resume(struct pci_dev *pdev); | ||
83 | #endif | ||
77 | static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); | 84 | static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); |
78 | static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); | 85 | static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); |
79 | static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val); | 86 | static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val); |
@@ -85,6 +92,7 @@ static void vt6420_bmdma_start(struct ata_queued_cmd *qc); | |||
85 | static int vt6421_pata_cable_detect(struct ata_port *ap); | 92 | static int vt6421_pata_cable_detect(struct ata_port *ap); |
86 | static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev); | 93 | static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev); |
87 | static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); | 94 | static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); |
95 | static void vt6421_error_handler(struct ata_port *ap); | ||
88 | 96 | ||
89 | static const struct pci_device_id svia_pci_tbl[] = { | 97 | static const struct pci_device_id svia_pci_tbl[] = { |
90 | { PCI_VDEVICE(VIA, 0x5337), vt6420 }, | 98 | { PCI_VDEVICE(VIA, 0x5337), vt6420 }, |
@@ -105,7 +113,7 @@ static struct pci_driver svia_pci_driver = { | |||
105 | .probe = svia_init_one, | 113 | .probe = svia_init_one, |
106 | #ifdef CONFIG_PM_SLEEP | 114 | #ifdef CONFIG_PM_SLEEP |
107 | .suspend = ata_pci_device_suspend, | 115 | .suspend = ata_pci_device_suspend, |
108 | .resume = ata_pci_device_resume, | 116 | .resume = svia_pci_device_resume, |
109 | #endif | 117 | #endif |
110 | .remove = ata_pci_remove_one, | 118 | .remove = ata_pci_remove_one, |
111 | }; | 119 | }; |
@@ -137,6 +145,7 @@ static struct ata_port_operations vt6421_sata_ops = { | |||
137 | .inherits = &svia_base_ops, | 145 | .inherits = &svia_base_ops, |
138 | .scr_read = svia_scr_read, | 146 | .scr_read = svia_scr_read, |
139 | .scr_write = svia_scr_write, | 147 | .scr_write = svia_scr_write, |
148 | .error_handler = vt6421_error_handler, | ||
140 | }; | 149 | }; |
141 | 150 | ||
142 | static struct ata_port_operations vt8251_ops = { | 151 | static struct ata_port_operations vt8251_ops = { |
@@ -536,7 +545,36 @@ static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) | |||
536 | return 0; | 545 | return 0; |
537 | } | 546 | } |
538 | 547 | ||
539 | static void svia_configure(struct pci_dev *pdev, int board_id) | 548 | static void svia_wd_fix(struct pci_dev *pdev) |
549 | { | ||
550 | u8 tmp8; | ||
551 | |||
552 | pci_read_config_byte(pdev, 0x52, &tmp8); | ||
553 | pci_write_config_byte(pdev, 0x52, tmp8 | BIT(2)); | ||
554 | } | ||
555 | |||
556 | static void vt6421_error_handler(struct ata_port *ap) | ||
557 | { | ||
558 | struct svia_priv *hpriv = ap->host->private_data; | ||
559 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
560 | u32 serror; | ||
561 | |||
562 | /* see svia_configure() for description */ | ||
563 | if (!hpriv->wd_workaround) { | ||
564 | svia_scr_read(&ap->link, SCR_ERROR, &serror); | ||
565 | if (serror == 0x1000500) { | ||
566 | ata_port_warn(ap, "Incompatible drive: enabling workaround. This slows down transfer rate to ~60 MB/s"); | ||
567 | svia_wd_fix(pdev); | ||
568 | hpriv->wd_workaround = true; | ||
569 | ap->link.eh_context.i.flags |= ATA_EHI_QUIET; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | ata_sff_error_handler(ap); | ||
574 | } | ||
575 | |||
576 | static void svia_configure(struct pci_dev *pdev, int board_id, | ||
577 | struct svia_priv *hpriv) | ||
540 | { | 578 | { |
541 | u8 tmp8; | 579 | u8 tmp8; |
542 | 580 | ||
@@ -593,11 +631,15 @@ static void svia_configure(struct pci_dev *pdev, int board_id) | |||
593 | * https://bugzilla.kernel.org/show_bug.cgi?id=15173 | 631 | * https://bugzilla.kernel.org/show_bug.cgi?id=15173 |
594 | * http://article.gmane.org/gmane.linux.ide/46352 | 632 | * http://article.gmane.org/gmane.linux.ide/46352 |
595 | * http://thread.gmane.org/gmane.linux.kernel/1062139 | 633 | * http://thread.gmane.org/gmane.linux.kernel/1062139 |
634 | * | ||
635 | * As the fix slows down data transfer, apply it only if the error | ||
636 | * actually appears - see vt6421_error_handler() | ||
637 | * Apply the fix always on vt6420 as we don't know if SCR_ERROR can be | ||
638 | * read safely. | ||
596 | */ | 639 | */ |
597 | if (board_id == vt6420 || board_id == vt6421) { | 640 | if (board_id == vt6420) { |
598 | pci_read_config_byte(pdev, 0x52, &tmp8); | 641 | svia_wd_fix(pdev); |
599 | tmp8 |= 1 << 2; | 642 | hpriv->wd_workaround = true; |
600 | pci_write_config_byte(pdev, 0x52, tmp8); | ||
601 | } | 643 | } |
602 | } | 644 | } |
603 | 645 | ||
@@ -608,6 +650,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
608 | struct ata_host *host = NULL; | 650 | struct ata_host *host = NULL; |
609 | int board_id = (int) ent->driver_data; | 651 | int board_id = (int) ent->driver_data; |
610 | const unsigned *bar_sizes; | 652 | const unsigned *bar_sizes; |
653 | struct svia_priv *hpriv; | ||
611 | 654 | ||
612 | ata_print_version_once(&pdev->dev, DRV_VERSION); | 655 | ata_print_version_once(&pdev->dev, DRV_VERSION); |
613 | 656 | ||
@@ -647,11 +690,35 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
647 | if (rc) | 690 | if (rc) |
648 | return rc; | 691 | return rc; |
649 | 692 | ||
650 | svia_configure(pdev, board_id); | 693 | hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); |
694 | if (!hpriv) | ||
695 | return -ENOMEM; | ||
696 | host->private_data = hpriv; | ||
697 | |||
698 | svia_configure(pdev, board_id, hpriv); | ||
651 | 699 | ||
652 | pci_set_master(pdev); | 700 | pci_set_master(pdev); |
653 | return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, | 701 | return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, |
654 | IRQF_SHARED, &svia_sht); | 702 | IRQF_SHARED, &svia_sht); |
655 | } | 703 | } |
656 | 704 | ||
705 | #ifdef CONFIG_PM_SLEEP | ||
706 | static int svia_pci_device_resume(struct pci_dev *pdev) | ||
707 | { | ||
708 | struct ata_host *host = pci_get_drvdata(pdev); | ||
709 | struct svia_priv *hpriv = host->private_data; | ||
710 | int rc; | ||
711 | |||
712 | rc = ata_pci_device_do_resume(pdev); | ||
713 | if (rc) | ||
714 | return rc; | ||
715 | |||
716 | if (hpriv->wd_workaround) | ||
717 | svia_wd_fix(pdev); | ||
718 | ata_host_resume(host); | ||
719 | |||
720 | return 0; | ||
721 | } | ||
722 | #endif | ||
723 | |||
657 | module_pci_driver(svia_pci_driver); | 724 | module_pci_driver(svia_pci_driver); |