Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/jdolecek-ncq]: src/sys/dev/ic add support for NCQ on Gen IIe hardware
details: https://anonhg.NetBSD.org/src/rev/dc89ba9c0b9b
branches: jdolecek-ncq
changeset: 352665:dc89ba9c0b9b
user: jdolecek <jdolecek%NetBSD.org@localhost>
date: Mon Jun 12 21:38:50 2017 +0000
description:
add support for NCQ on Gen IIe hardware
mvsata_quetag_get()/put() pairs adjusted to work also for non-DMA code paths,
i.e. during probe; replaced wdcintr() call with local routine which uses
currently active command tag, rather than assuming always tag 0 on that
code path
~55MB/s -> ~80MB/s sequential read using fio(1) on a test HDD, quite nice
diffstat:
sys/dev/ic/mvsata.c | 96 +++++++++++++++++++++++++++++++++++++---------------
1 files changed, 68 insertions(+), 28 deletions(-)
diffs (truncated from 332 to 300 lines):
diff -r d1c4c522ecd9 -r dc89ba9c0b9b sys/dev/ic/mvsata.c
--- a/sys/dev/ic/mvsata.c Sat Jun 10 13:25:51 2017 +0000
+++ b/sys/dev/ic/mvsata.c Mon Jun 12 21:38:50 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: mvsata.c,v 1.35.6.8 2017/06/10 13:25:51 jdolecek Exp $ */
+/* $NetBSD: mvsata.c,v 1.35.6.9 2017/06/12 21:38:50 jdolecek Exp $ */
/*
* Copyright (c) 2008 KIYOHARA Takashi
* All rights reserved.
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.8 2017/06/10 13:25:51 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.9 2017/06/12 21:38:50 jdolecek Exp $");
#include "opt_mvsata.h"
@@ -159,6 +159,8 @@
#endif
#endif
+static int mvsata_nondma_handle(struct mvsata_port *);
+
static int mvsata_port_init(struct mvsata_hc *, int);
static int mvsata_wdc_reg_init(struct mvsata_port *, struct wdc_regs *);
#ifndef MVSATA_WITHOUTDMA
@@ -289,6 +291,7 @@
_fix_phy = mvsata_fix_phy_gen2;
#ifndef MVSATA_WITHOUTDMA
edma_setup_crqb = mvsata_edma_setup_crqb_gen2e;
+ sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_NCQ;
#endif
break;
}
@@ -401,6 +404,7 @@
if (cause & SATAHC_IC_SAINTCOAL)
MVSATA_HC_WRITE_4(mvhc, SATAHC_IC, ~SATAHC_IC_SAINTCOAL);
cause &= ~SATAHC_IC_SAINTCOAL;
+
for (port = 0; port < sc->sc_port; port++) {
mvport = mvhc->hc_ports[port];
@@ -413,7 +417,7 @@
}
if (cause & SATAHC_IC_SADEVINTERRUPT(port)) {
- wdcintr(&mvport->port_ata_channel);
+ (void) mvsata_nondma_handle(mvport);
MVSATA_HC_WRITE_4(mvhc, SATAHC_IC,
~SATAHC_IC_SADEVINTERRUPT(port));
handled = 1;
@@ -423,6 +427,35 @@
return handled;
}
+static int
+mvsata_nondma_handle(struct mvsata_port *mvport)
+{
+ struct ata_channel *chp = &mvport->port_ata_channel;
+ struct ata_xfer *xfer;
+ int ret, quetag;
+
+ /*
+ * The chip doesn't support several pending non-DMA commands,
+ * and the ata middle layer never issues several non-NCQ commands,
+ * so there must be exactly one active command at this moment.
+ */
+ for (quetag = 0; quetag < MVSATA_EDMAQ_LEN; quetag++) {
+ if ((mvport->port_quetagidx & __BIT(quetag)) == 0)
+ continue;
+
+ break;
+ }
+ KASSERT(quetag < MVSATA_EDMAQ_LEN);
+
+ xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, quetag);
+ chp->ch_flags &= ~ATACH_IRQ_WAIT;
+ KASSERT(xfer->c_intr != NULL);
+ ret = xfer->c_intr(chp, xfer, 1);
+ if (ret == 0) /* irq was not for us, still waiting for irq */
+ chp->ch_flags |= ATACH_IRQ_WAIT;
+ return (ret);
+}
+
int
mvsata_error(struct mvsata_port *mvport)
{
@@ -528,6 +561,7 @@
mvsata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
{
struct ata_channel *chp = drvp->chnl_softc;
+ struct mvsata_port *mvport = (struct mvsata_port *)chp;
struct atac_softc *atac = chp->ch_atac;
struct ata_bio *ata_bio = &xfer->c_bio;
@@ -535,6 +569,8 @@
", bcount=%ld\n", device_xname(atac->atac_dev), chp->ch_channel,
drvp->drive, ata_bio->blkno, ata_bio->bcount));
+ mvsata_quetag_get(mvport, xfer->c_slot);
+
if (atac->atac_cap & ATAC_CAP_NOIRQ)
ata_bio->flags |= ATA_POLL;
if (ata_bio->flags & ATA_POLL)
@@ -636,9 +672,7 @@
mvsata_exec_command(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
{
struct ata_channel *chp = drvp->chnl_softc;
-#ifdef MVSATA_DEBUG
struct mvsata_port *mvport = (struct mvsata_port *)chp;
-#endif
struct ata_command *ata_c = &xfer->c_ata_c;
int rv, s;
@@ -649,6 +683,8 @@
drvp->drive, ata_c->bcount, ata_c->r_lba, ata_c->r_count,
ata_c->r_features, ata_c->r_device, ata_c->r_command));
+ mvsata_quetag_get(mvport, xfer->c_slot);
+
if (ata_c->flags & AT_POLL)
xfer->c_flags |= C_POLL;
if (ata_c->flags & AT_WAIT)
@@ -747,8 +783,9 @@
struct scsipi_xfer *sc_xfer;
struct mvsata_softc *sc = device_private(adapt->adapt_dev);
struct atac_softc *atac = &sc->sc_wdcdev.sc_atac;
+ struct ata_channel *chp = atac->atac_channels[chan->chan_channel];
struct ata_xfer *xfer;
- int channel = chan->chan_channel;
+ struct mvsata_port *mvport = (struct mvsata_port *)chp;
int drive, s;
switch (req) {
@@ -762,13 +799,15 @@
scsipi_done(sc_xfer);
return;
}
- xfer = ata_get_xfer(atac->atac_channels[channel]);
+ xfer = ata_get_xfer(chp);
if (xfer == NULL) {
sc_xfer->error = XS_RESOURCE_SHORTAGE;
scsipi_done(sc_xfer);
return;
}
+ mvsata_quetag_get(mvport, xfer->c_slot);
+
if (sc_xfer->xs_control & XS_CTL_POLL)
xfer->c_flags |= C_POLL;
xfer->c_drive = drive;
@@ -781,7 +820,7 @@
xfer->c_kill_xfer = mvsata_atapi_kill_xfer;
xfer->c_dscpoll = 0;
s = splbio();
- ata_exec_xfer(atac->atac_channels[channel], xfer);
+ ata_exec_xfer(chp, xfer);
#ifdef DIAGNOSTIC
if ((sc_xfer->xs_control & XS_CTL_POLL) != 0 &&
(sc_xfer->xs_status & XS_STS_DONE) == 0)
@@ -972,9 +1011,12 @@
splx(s);
}
- if (drvp->drive_flags & (ATA_DRIVE_UDMA | ATA_DRIVE_DMA))
- if (drvp->drive_type == ATA_DRIVET_ATA)
+ if (drvp->drive_flags & (ATA_DRIVE_UDMA | ATA_DRIVE_DMA)) {
+ if (drvp->drive_flags & ATA_DRIVE_NCQ)
+ edma_mode = ncq;
+ else if (drvp->drive_type == ATA_DRIVET_ATA)
edma_mode = dma;
+ }
}
DPRINTF(("EDMA %sactive mode\n", (edma_mode == nodma) ? "not " : ""));
@@ -1406,6 +1448,7 @@
panic("mvsata_bio_kill_xfer");
}
ata_bio->r_error = WDCE_ABRT;
+ mvsata_quetag_put(mvport, xfer->c_slot);
(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
}
@@ -1432,6 +1475,7 @@
ata_bio->bcount = xfer->c_bcount;
/* mark controller inactive and free xfer */
+ mvsata_quetag_put(mvport, xfer->c_slot);
ata_deactivate_xfer(chp, xfer);
if (ata_waitdrain_check(chp, drive))
@@ -1731,6 +1775,7 @@
"mvsata_cmd_kill_xfer: unknown reason %d\n", reason);
panic("mvsata_cmd_kill_xfer");
}
+ mvsata_quetag_put(mvport, xfer->c_slot);
mvsata_wdc_cmd_done_end(chp, xfer);
}
@@ -1793,6 +1838,7 @@
}
}
+ mvsata_quetag_put(mvport, xfer->c_slot);
ata_deactivate_xfer(chp, xfer);
if (ata_c->flags & AT_POLL) {
@@ -2246,6 +2292,7 @@
"mvsata_atapi_kill_xfer: unknown reason %d\n", reason);
panic("mvsata_atapi_kill_xfer");
}
+ mvsata_quetag_put(mvport, xfer->c_slot);
ata_free_xfer(chp, xfer);
scsipi_done(sc_xfer);
}
@@ -2356,6 +2403,7 @@
static void
mvsata_atapi_done(struct ata_channel *chp, struct ata_xfer *xfer)
{
+ struct mvsata_port *mvport = (struct mvsata_port *)chp;
struct scsipi_xfer *sc_xfer = xfer->c_scsipi;
int drive = xfer->c_drive;
@@ -2364,7 +2412,7 @@
xfer->c_drive, (u_int)xfer->c_flags));
/* mark controller inactive and free the command */
-
+ mvsata_quetag_put(mvport, xfer->c_slot);
ata_deactivate_xfer(chp, xfer);
if (ata_waitdrain_check(chp, drive))
@@ -2420,17 +2468,14 @@
MVSATA_EDMAQ_INC(next);
if (next == erqqop) {
/* queue full */
- return EBUSY; /* XXX slot */
+ return EBUSY;
}
- mvsata_quetag_get(mvport, xfer->c_slot);
DPRINTFN(2, (" erqqip=%d, quetag=%d\n", erqqip, xfer->c_slot));
rv = mvsata_dma_bufload(mvport, xfer->c_slot, databuf, ata_bio->nbytes,
ata_bio->flags);
- if (rv != 0) {
- mvsata_quetag_put(mvport, xfer->c_slot);
+ if (rv != 0)
return rv;
- }
/* setup EDMA Physical Region Descriptors (ePRD) Table Data */
data_dmamap = mvport->port_reqtbl[xfer->c_slot].data_dmamap;
@@ -2543,6 +2588,7 @@
#endif
crpb = mvport->port_crpb + erpqop;
quetag = CRPB_CHOSTQUETAG(le16toh(crpb->id));
+
xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, quetag);
bus_dmamap_sync(mvport->port_dmat, mvport->port_eprd_dmamap,
@@ -2562,7 +2608,6 @@
ata_bio->error = ERR_DMA;
mvsata_dma_bufunload(mvport, quetag, ata_bio->flags);
- mvsata_quetag_put(mvport, quetag);
MVSATA_EDMAQ_INC(erpqop);
#if 1 /* XXXX: flags clears here, because necessary the atabus layer. */
@@ -2676,7 +2721,7 @@
mvport->port_reqtbl[i].eprd_offset,
MVSATA_EPRD_MAX_SIZE, BUS_DMASYNC_POSTWRITE);
mvsata_dma_bufunload(mvport, i, xfer->c_bio.flags);
- mvsata_quetag_put(mvport, i);
+ /* quetag freed by caller later */
continue;
}
@@ -2715,16 +2760,11 @@
device_xname(MVSATA_DEV2(mvport)), mvport->port_hc->hc,
mvport->port, sc_xfer->datalen, sc_xfer->xs_control));
- mvsata_quetag_get(mvport, xfer->c_slot);
- DPRINTFN(2, (" quetag=%d\n", xfer->c_slot));
-
rv = mvsata_dma_bufload(mvport, xfer->c_slot, databuf,
sc_xfer->datalen,
sc_xfer->xs_control & XS_CTL_DATA_IN ? ATA_READ : 0);
- if (rv != 0) {
- mvsata_quetag_put(mvport, xfer->c_slot);
+ if (rv != 0)
return rv;
- }
/* setup EDMA Physical Region Descriptors (ePRD) Table Data */
data_dmamap = mvport->port_reqtbl[xfer->c_slot].data_dmamap;
@@ -2841,7 +2881,7 @@
chp = &mvport->port_ata_channel;
chp->ch_channel = channel;
chp->ch_atac = &sc->sc_wdcdev.sc_atac;
Home |
Main Index |
Thread Index |
Old Index