diff options
-rw-r--r-- | drivers/ata/ata_piix.c | 20 | ||||
-rw-r--r-- | drivers/ata/libata-sff.c | 35 | ||||
-rw-r--r-- | include/linux/libata.h | 1 |
3 files changed, 48 insertions, 8 deletions
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index b5f614b9c245..c33806654e46 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c | |||
@@ -173,6 +173,7 @@ static int piix_sidpr_scr_read(struct ata_link *link, | |||
173 | unsigned int reg, u32 *val); | 173 | unsigned int reg, u32 *val); |
174 | static int piix_sidpr_scr_write(struct ata_link *link, | 174 | static int piix_sidpr_scr_write(struct ata_link *link, |
175 | unsigned int reg, u32 val); | 175 | unsigned int reg, u32 val); |
176 | static bool piix_irq_check(struct ata_port *ap); | ||
176 | #ifdef CONFIG_PM | 177 | #ifdef CONFIG_PM |
177 | static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); | 178 | static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); |
178 | static int piix_pci_device_resume(struct pci_dev *pdev); | 179 | static int piix_pci_device_resume(struct pci_dev *pdev); |
@@ -317,8 +318,13 @@ static struct scsi_host_template piix_sht = { | |||
317 | ATA_BMDMA_SHT(DRV_NAME), | 318 | ATA_BMDMA_SHT(DRV_NAME), |
318 | }; | 319 | }; |
319 | 320 | ||
320 | static struct ata_port_operations piix_pata_ops = { | 321 | static struct ata_port_operations piix_sata_ops = { |
321 | .inherits = &ata_bmdma32_port_ops, | 322 | .inherits = &ata_bmdma32_port_ops, |
323 | .sff_irq_check = piix_irq_check, | ||
324 | }; | ||
325 | |||
326 | static struct ata_port_operations piix_pata_ops = { | ||
327 | .inherits = &piix_sata_ops, | ||
322 | .cable_detect = ata_cable_40wire, | 328 | .cable_detect = ata_cable_40wire, |
323 | .set_piomode = piix_set_piomode, | 329 | .set_piomode = piix_set_piomode, |
324 | .set_dmamode = piix_set_dmamode, | 330 | .set_dmamode = piix_set_dmamode, |
@@ -336,10 +342,6 @@ static struct ata_port_operations ich_pata_ops = { | |||
336 | .set_dmamode = ich_set_dmamode, | 342 | .set_dmamode = ich_set_dmamode, |
337 | }; | 343 | }; |
338 | 344 | ||
339 | static struct ata_port_operations piix_sata_ops = { | ||
340 | .inherits = &ata_bmdma32_port_ops, | ||
341 | }; | ||
342 | |||
343 | static struct ata_port_operations piix_sidpr_sata_ops = { | 345 | static struct ata_port_operations piix_sidpr_sata_ops = { |
344 | .inherits = &piix_sata_ops, | 346 | .inherits = &piix_sata_ops, |
345 | .hardreset = sata_std_hardreset, | 347 | .hardreset = sata_std_hardreset, |
@@ -970,6 +972,14 @@ static int piix_sidpr_scr_write(struct ata_link *link, | |||
970 | return 0; | 972 | return 0; |
971 | } | 973 | } |
972 | 974 | ||
975 | static bool piix_irq_check(struct ata_port *ap) | ||
976 | { | ||
977 | if (unlikely(!ap->ioaddr.bmdma_addr)) | ||
978 | return false; | ||
979 | |||
980 | return ap->ops->bmdma_status(ap) & ATA_DMA_INTR; | ||
981 | } | ||
982 | |||
973 | #ifdef CONFIG_PM | 983 | #ifdef CONFIG_PM |
974 | static int piix_broken_suspend(void) | 984 | static int piix_broken_suspend(void) |
975 | { | 985 | { |
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index c62ed13b0596..c2661ea70330 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c | |||
@@ -1763,7 +1763,7 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) | |||
1763 | { | 1763 | { |
1764 | struct ata_host *host = dev_instance; | 1764 | struct ata_host *host = dev_instance; |
1765 | unsigned int i; | 1765 | unsigned int i; |
1766 | unsigned int handled = 0; | 1766 | unsigned int handled = 0, polling = 0; |
1767 | unsigned long flags; | 1767 | unsigned long flags; |
1768 | 1768 | ||
1769 | /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ | 1769 | /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ |
@@ -1777,8 +1777,37 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) | |||
1777 | continue; | 1777 | continue; |
1778 | 1778 | ||
1779 | qc = ata_qc_from_tag(ap, ap->link.active_tag); | 1779 | qc = ata_qc_from_tag(ap, ap->link.active_tag); |
1780 | if (qc && !(qc->tf.flags & ATA_TFLAG_POLLING)) | 1780 | if (qc) { |
1781 | handled |= ata_sff_host_intr(ap, qc); | 1781 | if (!(qc->tf.flags & ATA_TFLAG_POLLING)) |
1782 | handled |= ata_sff_host_intr(ap, qc); | ||
1783 | else | ||
1784 | polling |= 1 << i; | ||
1785 | } | ||
1786 | } | ||
1787 | |||
1788 | /* | ||
1789 | * If no port was expecting IRQ but the controller is actually | ||
1790 | * asserting IRQ line, nobody cared will ensue. Check IRQ | ||
1791 | * pending status if available and clear spurious IRQ. | ||
1792 | */ | ||
1793 | if (!handled) { | ||
1794 | for (i = 0; i < host->n_ports; i++) { | ||
1795 | struct ata_port *ap = host->ports[i]; | ||
1796 | |||
1797 | if (polling & (1 << i)) | ||
1798 | continue; | ||
1799 | |||
1800 | if (!ap->ops->sff_irq_check || | ||
1801 | !ap->ops->sff_irq_check(ap)) | ||
1802 | continue; | ||
1803 | |||
1804 | if (printk_ratelimit()) | ||
1805 | ata_port_printk(ap, KERN_INFO, | ||
1806 | "clearing spurious IRQ\n"); | ||
1807 | |||
1808 | ap->ops->sff_check_status(ap); | ||
1809 | ap->ops->sff_irq_clear(ap); | ||
1810 | } | ||
1782 | } | 1811 | } |
1783 | 1812 | ||
1784 | spin_unlock_irqrestore(&host->lock, flags); | 1813 | spin_unlock_irqrestore(&host->lock, flags); |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 73112250862c..5fb888462359 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -857,6 +857,7 @@ struct ata_port_operations { | |||
857 | unsigned int (*sff_data_xfer)(struct ata_device *dev, | 857 | unsigned int (*sff_data_xfer)(struct ata_device *dev, |
858 | unsigned char *buf, unsigned int buflen, int rw); | 858 | unsigned char *buf, unsigned int buflen, int rw); |
859 | u8 (*sff_irq_on)(struct ata_port *); | 859 | u8 (*sff_irq_on)(struct ata_port *); |
860 | bool (*sff_irq_check)(struct ata_port *); | ||
860 | void (*sff_irq_clear)(struct ata_port *); | 861 | void (*sff_irq_clear)(struct ata_port *); |
861 | 862 | ||
862 | void (*bmdma_setup)(struct ata_queued_cmd *qc); | 863 | void (*bmdma_setup)(struct ata_queued_cmd *qc); |