Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev add support for PERFORMANT mode, and allow MSI/MSI-X...



details:   https://anonhg.NetBSD.org/src/rev/cecc40ecca31
branches:  trunk
changeset: 935953:cecc40ecca31
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Tue Jul 14 10:37:30 2020 +0000

description:
add support for PERFORMANT mode, and allow MSI/MSI-X (only) for adapters which
support it

code adapted from FreeBSD, but with fix for setting the performant bit
and pull count on command submittion as seen in hpsa Linux driver

tested with INTx and MSI-X on HP Smart Array 11

thanks to Andreas Gustafsson for initial testing, and providing
access to test machine

diffstat:

 sys/dev/ic/ciss.c      |  415 +++++++++++++++++++++++++++++++++++++-----------
 sys/dev/ic/cissreg.h   |   58 +++++-
 sys/dev/ic/cissvar.h   |   14 +-
 sys/dev/pci/ciss_pci.c |   60 +++++-
 4 files changed, 428 insertions(+), 119 deletions(-)

diffs (truncated from 828 to 300 lines):

diff -r 031462748db0 -r cecc40ecca31 sys/dev/ic/ciss.c
--- a/sys/dev/ic/ciss.c Tue Jul 14 10:26:34 2020 +0000
+++ b/sys/dev/ic/ciss.c Tue Jul 14 10:37:30 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ciss.c,v 1.43 2020/07/10 14:23:56 jdolecek Exp $       */
+/*     $NetBSD: ciss.c,v 1.44 2020/07/14 10:37:30 jdolecek Exp $       */
 /*     $OpenBSD: ciss.c,v 1.68 2013/05/30 16:15:02 deraadt Exp $       */
 
 /*
@@ -19,7 +19,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ciss.c,v 1.43 2020/07/10 14:23:56 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ciss.c,v 1.44 2020/07/14 10:37:30 jdolecek Exp $");
 
 #include "bio.h"
 
@@ -128,6 +128,98 @@
        mutex_exit(&sc->sc_mutex);
 }
 
+static int
+ciss_init_perf(struct ciss_softc *sc)
+{
+       struct ciss_perf_config *pc = &sc->perfcfg;
+       int error, total, rseg;
+
+       if (sc->cfg.max_perfomant_mode_cmds)
+               sc->maxcmd = sc->cfg.max_perfomant_mode_cmds;
+
+       bus_space_read_region_4(sc->sc_iot, sc->cfg_ioh,
+           sc->cfgoff + sc->cfg.troff,
+           (u_int32_t *)pc, sizeof(*pc) / 4);
+
+       total = sizeof(uint64_t) * sc->maxcmd;
+
+       if ((error = bus_dmamem_alloc(sc->sc_dmat, total, PAGE_SIZE, 0,
+           sc->replyseg, 1, &rseg, BUS_DMA_WAITOK))) {
+               aprint_error(": cannot allocate perf area (%d)\n", error);
+               return -1;
+       }
+
+       if ((error = bus_dmamem_map(sc->sc_dmat, sc->replyseg, rseg, total,
+           (void **)&sc->perf_reply, BUS_DMA_WAITOK))) {
+               aprint_error(": cannot map perf area (%d)\n", error);
+               bus_dmamem_free(sc->sc_dmat, sc->replyseg, 1);
+               return -1;
+       }
+
+       if ((error = bus_dmamap_create(sc->sc_dmat, total, 1,
+           total, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &sc->replymap))) {
+               aprint_error(": cannot create perf dmamap (%d)\n", error);
+               bus_dmamem_unmap(sc->sc_dmat, sc->perf_reply, total);
+               sc->perf_reply = NULL;
+               bus_dmamem_free(sc->sc_dmat, sc->replyseg, 1);
+               return -1;
+       }
+
+       if ((error = bus_dmamap_load(sc->sc_dmat, sc->replymap, sc->perf_reply,
+           total, NULL, BUS_DMA_WAITOK))) {
+               aprint_error(": cannot load perf dmamap (%d)\n", error);
+               bus_dmamap_destroy(sc->sc_dmat, sc->replymap);
+               bus_dmamem_unmap(sc->sc_dmat, sc->perf_reply, total);
+               sc->perf_reply = NULL;
+               bus_dmamem_free(sc->sc_dmat, sc->replyseg, 1);
+               return -1;
+       }
+
+       memset(sc->perf_reply, 0, total);
+
+       sc->perf_cycle = 0x1;
+       sc->perf_rqidx = 0;
+
+       /*
+       * Preload the fetch table with common command sizes.  This allows the
+       * hardware to not waste bus cycles for typical i/o commands, but also
+       * not tax the driver to be too exact in choosing sizes.  The table
+       * is optimized for page-aligned i/o's, but since most i/o comes
+       * from the various pagers, it's a reasonable assumption to make.
+       */
+#define CISS_FETCH_COUNT(x)    \
+    (sizeof(struct ciss_cmd) + sizeof(struct ciss_sg_entry) * (x - 1) + 15) / 16
+
+       pc->fetch_count[CISS_SG_FETCH_NONE] = CISS_FETCH_COUNT(0);
+       pc->fetch_count[CISS_SG_FETCH_1] = CISS_FETCH_COUNT(1);
+       pc->fetch_count[CISS_SG_FETCH_2] = CISS_FETCH_COUNT(2);
+       pc->fetch_count[CISS_SG_FETCH_4] = CISS_FETCH_COUNT(4);
+       pc->fetch_count[CISS_SG_FETCH_8] = CISS_FETCH_COUNT(8);
+       pc->fetch_count[CISS_SG_FETCH_16] = CISS_FETCH_COUNT(16);
+       pc->fetch_count[CISS_SG_FETCH_32] = CISS_FETCH_COUNT(32);
+       pc->fetch_count[CISS_SG_FETCH_MAX] = (sc->ccblen + 15) / 16;
+
+       pc->rq_size = sc->maxcmd;
+       pc->rq_count = 1;       /* Hardcode for a single queue */
+       pc->rq_bank_hi = 0;
+       pc->rq_bank_lo = 0;
+       pc->rq[0].rq_addr_hi = 0x0;
+       pc->rq[0].rq_addr_lo = sc->replymap->dm_segs[0].ds_addr;
+
+       /*
+        * Write back the changed configuration. Tt will be picked up
+        * by controller together with general configuration later on.
+        */
+       bus_space_write_region_4(sc->sc_iot, sc->cfg_ioh,
+           sc->cfgoff + sc->cfg.troff,
+           (u_int32_t *)pc, sizeof(*pc) / 4);
+       bus_space_barrier(sc->sc_iot, sc->cfg_ioh,
+           sc->cfgoff + sc->cfg.troff, sizeof(*pc),
+           BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
+
+       return 0;
+}
+
 int
 ciss_attach(struct ciss_softc *sc)
 {
@@ -138,27 +230,41 @@
        int error, i, total, rseg, maxfer;
        paddr_t pa;
 
-       bus_space_read_region_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff,
-           (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
-
        if (sc->cfg.signature != CISS_SIGNATURE) {
                aprint_error(": bad sign 0x%08x\n", sc->cfg.signature);
                return -1;
        }
 
-       if (!(sc->cfg.methods & CISS_METH_SIMPL)) {
-               aprint_error(": not simple 0x%08x\n", sc->cfg.methods);
+       if (!(sc->cfg.methods & (CISS_METH_SIMPL|CISS_METH_PERF))) {
+               aprint_error(": no supported method 0x%08x\n", sc->cfg.methods);
                return -1;
        }
 
-       sc->cfg.rmethod = CISS_METH_SIMPL;
+       if (!sc->cfg.maxsg)
+               sc->cfg.maxsg = MAXPHYS / PAGE_SIZE + 1;
+
+       sc->maxcmd = sc->cfg.maxcmd;
+       sc->maxsg = sc->cfg.maxsg;
+       if (sc->maxsg > MAXPHYS / PAGE_SIZE + 1)
+               sc->maxsg = MAXPHYS / PAGE_SIZE + 1;
+       i = sizeof(struct ciss_ccb) +
+           sizeof(ccb->ccb_cmd.sgl[0]) * (sc->maxsg - 1);
+       for (sc->ccblen = 0x10; sc->ccblen < i; sc->ccblen <<= 1);
+
        sc->cfg.paddr_lim = 0;                  /* 32bit addrs */
        sc->cfg.int_delay = 0;                  /* disable coalescing */
        sc->cfg.int_count = 0;
        strlcpy(sc->cfg.hostname, "HUMPPA", sizeof(sc->cfg.hostname));
        sc->cfg.driverf |= CISS_DRV_PRF;        /* enable prefetch */
-       if (!sc->cfg.maxsg)
-               sc->cfg.maxsg = MAXPHYS / PAGE_SIZE + 1;
+       if (CISS_PERF_SUPPORTED(sc)) {
+               sc->cfg.rmethod = CISS_METH_PERF | CISS_METH_SHORT_TAG;
+               if (ciss_init_perf(sc) != 0) {
+                       /* Don't try to fallback, just bail out */
+                       return -1;
+               }
+       } else {
+               sc->cfg.rmethod = CISS_METH_SIMPL;
+       }
 
        bus_space_write_region_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff,
            (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
@@ -178,15 +284,15 @@
        }
 
        if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IDB) & CISS_IDB_CFG) {
-               printf(": cannot set config\n");
+               aprint_error(": cannot set config\n");
                return -1;
        }
 
        bus_space_read_region_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff,
            (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
 
-       if (!(sc->cfg.amethod & CISS_METH_SIMPL)) {
-               printf(": cannot simplify 0x%08x\n", sc->cfg.amethod);
+       if (!(sc->cfg.amethod & (CISS_METH_SIMPL|CISS_METH_PERF))) {
+               aprint_error(": cannot set method 0x%08x\n", sc->cfg.amethod);
                return -1;
        }
 
@@ -210,13 +316,6 @@
        mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
        mutex_init(&sc->sc_mutex_scratch, MUTEX_DEFAULT, IPL_VM);
        cv_init(&sc->sc_condvar, "ciss_cmd");
-       sc->maxcmd = sc->cfg.maxcmd;
-       sc->maxsg = sc->cfg.maxsg;
-       if (sc->maxsg > MAXPHYS / PAGE_SIZE + 1)
-               sc->maxsg = MAXPHYS / PAGE_SIZE + 1;
-       i = sizeof(struct ciss_ccb) +
-           sizeof(ccb->ccb_cmd.sgl[0]) * (sc->maxsg - 1);
-       for (sc->ccblen = 0x10; sc->ccblen < i; sc->ccblen <<= 1);
 
        total = sc->ccblen * sc->maxcmd;
        if ((error = bus_dmamem_alloc(sc->sc_dmat, total, PAGE_SIZE, 0,
@@ -329,6 +428,9 @@
                aprint_normal(", 64bit fifo");
        else if (sc->cfg.methods & CISS_METH_FIFO64_RRO)
                aprint_normal(", 64bit fifo rro");
+       aprint_normal(", method %s %#x",
+           CISS_IS_PERF(sc) ? "perf" : "simple",
+           sc->cfg.amethod);
        aprint_normal("\n");
 
        mutex_exit(&sc->sc_mutex_scratch);
@@ -431,61 +533,110 @@
        minphys(bp);
 }
 
-static struct ciss_ccb *
-ciss_poll1(struct ciss_softc *sc)
+static void
+ciss_enqueue(struct ciss_softc *sc, ciss_queue_head *q, uint32_t id)
 {
        struct ciss_ccb *ccb;
-       uint32_t id;
-
-       if (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_ISR) & sc->iem)) {
-               CISS_DPRINTF(CISS_D_CMD, ("N"));
-               return NULL;
-       }
 
-       if (sc->cfg.methods & CISS_METH_FIFO64) {
-               if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_OUTQ64_HI) ==
-                   0xffffffff) {
-                       CISS_DPRINTF(CISS_D_CMD, ("Q"));
-                       return NULL;
-               }
-               id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_OUTQ64_LO);
-       } else if (sc->cfg.methods & CISS_METH_FIFO64_RRO) {
-               id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_OUTQ64_LO);
-               if (id == 0xffffffff) {
-                       CISS_DPRINTF(CISS_D_CMD, ("Q"));
-                       return NULL;
-               }
-               (void)bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_OUTQ64_HI);
-       } else {
-               id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_OUTQ);
-               if (id == 0xffffffff) {
-                       CISS_DPRINTF(CISS_D_CMD, ("Q"));
-                       return NULL;
-               }
-       }
+       KASSERT(mutex_owned(&sc->sc_mutex));
 
-       CISS_DPRINTF(CISS_D_CMD, ("got=0x%x ", id));
+       KASSERT((id >> 2) <= sc->maxcmd);
        ccb = (struct ciss_ccb *) ((char *)sc->ccbs + (id >> 2) * sc->ccblen);
        ccb->ccb_cmd.id = htole32(id);
        ccb->ccb_cmd.id_hi = htole32(0);
-       return ccb;
+       TAILQ_INSERT_TAIL(q, ccb, ccb_link);
+}
+
+static void
+ciss_completed_simple(struct ciss_softc *sc, ciss_queue_head *q)
+{
+       uint32_t id;
+
+       KASSERT(mutex_owned(&sc->sc_mutex));
+
+       for (;;) {
+               if (sc->cfg.methods & CISS_METH_FIFO64) {
+                       if (bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                           CISS_OUTQ64_HI) == 0xffffffff) {
+                               CISS_DPRINTF(CISS_D_CMD, ("Q"));
+                               break;
+                       }
+                       id = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                           CISS_OUTQ64_LO);
+               } else if (sc->cfg.methods & CISS_METH_FIFO64_RRO) {
+                       id = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                           CISS_OUTQ64_LO);
+                       if (id == 0xffffffff) {
+                               CISS_DPRINTF(CISS_D_CMD, ("Q"));
+                               break;
+                       }
+                       (void)bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                           CISS_OUTQ64_HI);
+               } else {
+                       id = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                           CISS_OUTQ);
+                       if (id == 0xffffffff) {
+                               CISS_DPRINTF(CISS_D_CMD, ("Q"));
+                               break;
+                       }
+               }
+
+               CISS_DPRINTF(CISS_D_CMD, ("got=0x%x ", id));
+               ciss_enqueue(sc, q, id);
+       }
+}
+
+static void
+ciss_completed_perf(struct ciss_softc *sc, ciss_queue_head *q)



Home | Main Index | Thread Index | Old Index