aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/sata_via.c81
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
76struct svia_priv {
77 bool wd_workaround;
78};
79
76static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 80static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
81#ifdef CONFIG_PM_SLEEP
82static int svia_pci_device_resume(struct pci_dev *pdev);
83#endif
77static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); 84static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
78static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); 85static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
79static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val); 86static 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);
85static int vt6421_pata_cable_detect(struct ata_port *ap); 92static int vt6421_pata_cable_detect(struct ata_port *ap);
86static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev); 93static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
87static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); 94static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
95static void vt6421_error_handler(struct ata_port *ap);
88 96
89static const struct pci_device_id svia_pci_tbl[] = { 97static 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
142static struct ata_port_operations vt8251_ops = { 151static 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
539static void svia_configure(struct pci_dev *pdev, int board_id) 548static 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
556static 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
576static 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
706static 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
657module_pci_driver(svia_pci_driver); 724module_pci_driver(svia_pci_driver);