diff options
author | Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> | 2020-03-26 18:58:16 +0300 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2020-03-26 19:28:20 +0300 |
commit | 61a11986d33d01dbef745d49c0536961eb06d2f1 (patch) | |
tree | 83ef9addb5af9b47c7168721eca95461b6e86f6f /drivers/ata/libata-sata.c | |
parent | 78c97c80d76b0590fc6ff5e20f4b18f105aa4fae (diff) | |
download | linux-61a11986d33d01dbef745d49c0536961eb06d2f1.tar.xz |
ata: move ata_qc_complete_multiple() to libata-sata.c
* move ata_qc_complete_multiple() to libata-sata.c
Code size savings on m68k arch using (modified) atari_defconfig:
text data bss dec hex filename
before:
32559 572 40 33171 8193 drivers/ata/libata-core.o
after:
32162 572 40 32774 8006 drivers/ata/libata-core.o
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/ata/libata-sata.c')
-rw-r--r-- | drivers/ata/libata-sata.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 05a1872ba329..849582e0d653 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -604,6 +604,65 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, EXPORT_SYMBOL_GPL(sata_link_hardreset); /** + * ata_qc_complete_multiple - Complete multiple qcs successfully + * @ap: port in question + * @qc_active: new qc_active mask + * + * Complete in-flight commands. This functions is meant to be + * called from low-level driver's interrupt routine to complete + * requests normally. ap->qc_active and @qc_active is compared + * and commands are completed accordingly. + * + * Always use this function when completing multiple NCQ commands + * from IRQ handlers instead of calling ata_qc_complete() + * multiple times to keep IRQ expect status properly in sync. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Number of completed commands on success, -errno otherwise. + */ +int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active) +{ + u64 done_mask, ap_qc_active = ap->qc_active; + int nr_done = 0; + + /* + * If the internal tag is set on ap->qc_active, then we care about + * bit0 on the passed in qc_active mask. Move that bit up to match + * the internal tag. + */ + if (ap_qc_active & (1ULL << ATA_TAG_INTERNAL)) { + qc_active |= (qc_active & 0x01) << ATA_TAG_INTERNAL; + qc_active ^= qc_active & 0x01; + } + + done_mask = ap_qc_active ^ qc_active; + + if (unlikely(done_mask & qc_active)) { + ata_port_err(ap, "illegal qc_active transition (%08llx->%08llx)\n", + ap->qc_active, qc_active); + return -EINVAL; + } + + while (done_mask) { + struct ata_queued_cmd *qc; + unsigned int tag = __ffs64(done_mask); + + qc = ata_qc_from_tag(ap, tag); + if (qc) { + ata_qc_complete(qc); + nr_done++; + } + done_mask &= ~(1ULL << tag); + } + + return nr_done; +} +EXPORT_SYMBOL_GPL(ata_qc_complete_multiple); + +/** * ata_slave_link_init - initialize slave link * @ap: port to initialize slave link for * |