libata: add ata_ratelimit(), use it in AHCI driver irq handler
authorJeff Garzik <jgarzik@pobox.com>
Wed, 5 Oct 2005 06:58:32 +0000 (02:58 -0400)
committerJeff Garzik <jgarzik@pobox.com>
Wed, 5 Oct 2005 06:58:32 +0000 (02:58 -0400)
drivers/scsi/ahci.c
drivers/scsi/libata-core.c
include/linux/libata.h

index c2c8fa828e24e9d227aaf93a5efc4367dab40872..5ec866b004793472cace66e971640922b75d9a79 100644 (file)
@@ -672,17 +672,36 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
 
         for (i = 0; i < host_set->n_ports; i++) {
                struct ata_port *ap;
-               u32 tmp;
 
-               VPRINTK("port %u\n", i);
+               if (!(irq_stat & (1 << i)))
+                       continue;
+
                ap = host_set->ports[i];
-               tmp = irq_stat & (1 << i);
-               if (tmp && ap) {
+               if (ap) {
                        struct ata_queued_cmd *qc;
                        qc = ata_qc_from_tag(ap, ap->active_tag);
-                       if (ahci_host_intr(ap, qc))
-                               irq_ack |= (1 << i);
+                       if (!ahci_host_intr(ap, qc))
+                               if (ata_ratelimit()) {
+                                       struct pci_dev *pdev =
+                                         to_pci_dev(ap->host_set->dev);
+                                       printk(KERN_WARNING
+                                         "ahci(%s): unhandled interrupt on port %u\n",
+                                         pci_name(pdev), i);
+                               }
+
+                       VPRINTK("port %u\n", i);
+               } else {
+                       VPRINTK("port %u (no irq)\n", i);
+                       if (ata_ratelimit()) {
+                               struct pci_dev *pdev =
+                                 to_pci_dev(ap->host_set->dev);
+                               printk(KERN_WARNING
+                                 "ahci(%s): interrupt on disabled port %u\n",
+                                 pci_name(pdev), i);
+                       }
                }
+
+               irq_ack |= (1 << i);
        }
 
        if (irq_ack) {
index f0894bfa908b3953401e4ffb8456f33211d95dc1..ceffaef37d17d824a0d4e5051137e1708d01b1ce 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/completion.h>
 #include <linux/suspend.h>
 #include <linux/workqueue.h>
+#include <linux/jiffies.h>
 #include <scsi/scsi.h>
 #include "scsi.h"
 #include "scsi_priv.h"
@@ -4688,6 +4689,27 @@ static void __exit ata_exit(void)
 module_init(ata_init);
 module_exit(ata_exit);
 
+static unsigned long ratelimit_time;
+static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED;
+
+int ata_ratelimit(void)
+{
+       int rc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ata_ratelimit_lock, flags);
+
+       if (time_after(jiffies, ratelimit_time)) {
+               rc = 1;
+               ratelimit_time = jiffies + (HZ/5);
+       } else
+               rc = 0;
+
+       spin_unlock_irqrestore(&ata_ratelimit_lock, flags);
+
+       return rc;
+}
+
 /*
  * libata is essentially a library of internal helper functions for
  * low-level ATA host controller drivers.  As such, the API/ABI is
@@ -4729,6 +4751,7 @@ EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
 EXPORT_SYMBOL_GPL(ata_port_disable);
+EXPORT_SYMBOL_GPL(ata_ratelimit);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_error);
index 4d45179872cccc591e18bbe40c469e67480bef8f..7929cfc9318d0b42aa7fb7da018987fd567fabef 100644 (file)
@@ -410,6 +410,8 @@ extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmn
 extern int ata_scsi_error(struct Scsi_Host *host);
 extern int ata_scsi_release(struct Scsi_Host *host);
 extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+extern int ata_ratelimit(void);
+
 /*
  * Default driver ops implementations
  */