From 67846b30171cc4d706125f630193a76a26bb334a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 5 Oct 2005 02:58:32 -0400 Subject: [PATCH] libata: add ata_ratelimit(), use it in AHCI driver irq handler --- drivers/scsi/ahci.c | 31 +++++++++++++++++++++++++------ drivers/scsi/libata-core.c | 23 +++++++++++++++++++++++ include/linux/libata.h | 2 ++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c2c8fa828e24..5ec866b00479 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -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) { diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f0894bfa908b..ceffaef37d17 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #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); diff --git a/include/linux/libata.h b/include/linux/libata.h index 4d45179872cc..7929cfc9318d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -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 */