aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/sata_qstor.c
diff options
context:
space:
mode:
authorMark Lord <liml@rtr.ca>2007-11-07 10:53:41 -0500
committerJeff Garzik <jeff@garzik.org>2007-11-08 13:08:41 -0500
commit904c7bad994e6e7f9997174e0b33fcc521862136 (patch)
tree496a8fdb73e5859cbc47ae09096f7dacc4081763 /drivers/ata/sata_qstor.c
parent12ee7d3ceb08e9ab99a6c17c5c6a387645a32658 (diff)
libata sata_qstor workaround for spurious interrupts
sata_qstor workaround for spurious interrupts. The qstor hardware generates spurious interrupts from time to time when switching in and out of packet mode. These eventually result in the IRQ being disabled, which kills other devices sharing this IRQ with us. This workaround isn't perfect, but it's about the best we can do for this hardware. Spurious interrupts will still happen, but won't be logged as such, and therefore won't cause the IRQ to be inadvertently disabled. Signed-off-by: Mark Lord <mlord@pobox.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/sata_qstor.c')
-rw-r--r--drivers/ata/sata_qstor.c38
1 files changed, 21 insertions, 17 deletions
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 9d3128ca3443..7446a335fc92 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -425,24 +425,27 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
425 if (ap && 425 if (ap &&
426 !(ap->flags & ATA_FLAG_DISABLED)) { 426 !(ap->flags & ATA_FLAG_DISABLED)) {
427 struct ata_queued_cmd *qc; 427 struct ata_queued_cmd *qc;
428 struct qs_port_priv *pp = ap->private_data; 428 struct qs_port_priv *pp;
429 if (!pp || pp->state != qs_state_mmio)
430 continue;
431 qc = ata_qc_from_tag(ap, ap->link.active_tag); 429 qc = ata_qc_from_tag(ap, ap->link.active_tag);
432 if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { 430 if (!qc || !(qc->flags & ATA_QCFLAG_ACTIVE)) {
433 431 /*
434 /* check main status, clearing INTRQ */ 432 * The qstor hardware generates spurious
435 u8 status = ata_check_status(ap); 433 * interrupts from time to time when switching
436 if ((status & ATA_BUSY)) 434 * in and out of packet mode.
437 continue; 435 * There's no obvious way to know if we're
438 DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", 436 * here now due to that, so just ack the irq
439 ap->print_id, qc->tf.protocol, status); 437 * and pretend we knew it was ours.. (ugh).
440 438 * This does not affect packet mode.
441 /* complete taskfile transaction */ 439 */
442 qc->err_mask |= ac_err_mask(status); 440 ata_check_status(ap);
443 ata_qc_complete(qc);
444 handled = 1; 441 handled = 1;
442 continue;
445 } 443 }
444 pp = ap->private_data;
445 if (!pp || pp->state != qs_state_mmio)
446 continue;
447 if (!(qc->tf.flags & ATA_TFLAG_POLLING))
448 handled |= ata_host_intr(ap, qc);
446 } 449 }
447 } 450 }
448 return handled; 451 return handled;
@@ -452,12 +455,13 @@ static irqreturn_t qs_intr(int irq, void *dev_instance)
452{ 455{
453 struct ata_host *host = dev_instance; 456 struct ata_host *host = dev_instance;
454 unsigned int handled = 0; 457 unsigned int handled = 0;
458 unsigned long flags;
455 459
456 VPRINTK("ENTER\n"); 460 VPRINTK("ENTER\n");
457 461
458 spin_lock(&host->lock); 462 spin_lock_irqsave(&host->lock, flags);
459 handled = qs_intr_pkt(host) | qs_intr_mmio(host); 463 handled = qs_intr_pkt(host) | qs_intr_mmio(host);
460 spin_unlock(&host->lock); 464 spin_unlock_irqrestore(&host->lock, flags);
461 465
462 VPRINTK("EXIT\n"); 466 VPRINTK("EXIT\n");
463 467