summaryrefslogtreecommitdiff
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r--drivers/ata/libata-core.c55
1 files changed, 36 insertions, 19 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 7f77c67d267c..63527aace6f8 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4819,22 +4819,7 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc)
dev->flags &= ~ATA_DFLAG_DUBIOUS_XFER;
}
-/**
- * ata_qc_complete - Complete an active ATA command
- * @qc: Command to complete
- *
- * Indicate to the mid and upper layers that an ATA command has
- * completed, with either an ok or not-ok status.
- *
- * Refrain from calling this function multiple times when
- * successfully completing multiple NCQ commands.
- * ata_qc_complete_multiple() should be used instead, which will
- * properly update IRQ expect state.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_qc_complete(struct ata_queued_cmd *qc)
+static void ata_qc_complete_raw(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -4913,6 +4898,27 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
}
/**
+ * ata_qc_complete - Complete an active ATA command
+ * @qc: Command to complete
+ *
+ * Indicate to the mid and upper layers that an ATA command has
+ * completed, with either an ok or not-ok status.
+ *
+ * Refrain from calling this function multiple times when
+ * successfully completing multiple NCQ commands.
+ * ata_qc_complete_multiple() should be used instead, which will
+ * properly update IRQ expect state.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_qc_complete(struct ata_queued_cmd *qc)
+{
+ unexpect_irq(qc->ap->irq_expect, false);
+ ata_qc_complete_raw(qc);
+}
+
+/**
* ata_qc_complete_multiple - Complete multiple qcs successfully
* @ap: port in question
* @qc_active: new qc_active mask
@@ -4937,6 +4943,8 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
int nr_done = 0;
u32 done_mask;
+ unexpect_irq(ap->irq_expect, false);
+
done_mask = ap->qc_active ^ qc_active;
if (unlikely(done_mask & qc_active)) {
@@ -4951,12 +4959,15 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
qc = ata_qc_from_tag(ap, tag);
if (qc) {
- ata_qc_complete(qc);
+ ata_qc_complete_raw(qc);
nr_done++;
}
done_mask &= ~(1 << tag);
}
+ if (ap->qc_active)
+ expect_irq(ap->irq_expect);
+
return nr_done;
}
@@ -5026,6 +5037,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
qc->err_mask |= ap->ops->qc_issue(qc);
if (unlikely(qc->err_mask))
goto err;
+ expect_irq(ap->irq_expect);
return;
sys_err:
@@ -6081,8 +6093,13 @@ int ata_host_activate(struct ata_host *host, int irq,
if (rc)
return rc;
- for (i = 0; i < host->n_ports; i++)
- ata_port_desc(host->ports[i], "irq %d", irq);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (!ata_port_is_dummy(ap))
+ ap->irq_expect = init_irq_expect(irq, host);
+ ata_port_desc(ap, "irq %d%s", irq, ap->irq_expect ? "+" : "");
+ }
rc = ata_host_register(host, sht);
/* if failed, just free the IRQ and leave ports alone */