aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/mpr
diff options
context:
space:
mode:
authorScott Long <scottl@FreeBSD.org>2017-09-11 01:51:27 +0000
committerScott Long <scottl@FreeBSD.org>2017-09-11 01:51:27 +0000
commit3c5ac992c76786af01081721995ae377131b3edc (patch)
tree9c2b8ace5c8fb0c275d0677870e24c9006aa5001 /sys/dev/mpr
parent5e66298138a2243c9de66734e678ec0c3ff2ec08 (diff)
Notes
Diffstat (limited to 'sys/dev/mpr')
-rw-r--r--sys/dev/mpr/mpr.c109
-rw-r--r--sys/dev/mpr/mpr_pci.c37
-rw-r--r--sys/dev/mpr/mpr_sas.c3
-rw-r--r--sys/dev/mpr/mprvar.h17
4 files changed, 140 insertions, 26 deletions
diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c
index b34630d955ba..c5df73003715 100644
--- a/sys/dev/mpr/mpr.c
+++ b/sys/dev/mpr/mpr.c
@@ -82,6 +82,7 @@ __FBSDID("$FreeBSD$");
static int mpr_diag_reset(struct mpr_softc *sc, int sleep_flag);
static int mpr_init_queues(struct mpr_softc *sc);
+static void mpr_resize_queues(struct mpr_softc *sc);
static int mpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag);
static int mpr_transition_operational(struct mpr_softc *sc);
static int mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching);
@@ -374,6 +375,46 @@ mpr_transition_operational(struct mpr_softc *sc)
return (error);
}
+static void
+mpr_resize_queues(struct mpr_softc *sc)
+{
+ int reqcr, prireqcr;
+
+ /*
+ * Size the queues. Since the reply queues always need one free
+ * entry, we'll deduct one reply message here. The LSI documents
+ * suggest instead to add a count to the request queue, but I think
+ * that it's better to deduct from reply queue.
+ */
+ prireqcr = MAX(1, sc->max_prireqframes);
+ prireqcr = MIN(prireqcr, sc->facts->HighPriorityCredit);
+
+ reqcr = MAX(2, sc->max_reqframes);
+ reqcr = MIN(reqcr, sc->facts->RequestCredit);
+
+ sc->num_reqs = prireqcr + reqcr;
+ sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes,
+ sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
+
+ /*
+ * Figure out the number of MSIx-based queues. If the firmware or
+ * user has done something crazy and not allowed enough credit for
+ * the queues to be useful then don't enable multi-queue.
+ */
+ if (sc->facts->MaxMSIxVectors < 2)
+ sc->msi_msgs = 1;
+
+ if (sc->msi_msgs > 1) {
+ sc->msi_msgs = MIN(sc->msi_msgs, mp_ncpus);
+ sc->msi_msgs = MIN(sc->msi_msgs, sc->facts->MaxMSIxVectors);
+ if (sc->num_reqs / sc->msi_msgs < 2)
+ sc->msi_msgs = 1;
+ }
+
+ mpr_dprint(sc, MPR_INIT, "Sized queues to q=%d reqs=%d replies=%d\n",
+ sc->msi_msgs, sc->num_reqs, sc->num_replies);
+}
+
/*
* This is called during attach and when re-initializing due to a Diag Reset.
* IOC Facts is used to allocate many of the structures needed by the driver.
@@ -530,13 +571,7 @@ mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching)
MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
sc->atomic_desc_capable = TRUE;
- /*
- * Size the queues. Since the reply queues always need one free
- * entry, we'll just deduct one reply message here.
- */
- sc->num_reqs = MIN(MPR_REQ_FRAMES, sc->facts->RequestCredit);
- sc->num_replies = MIN(MPR_REPLY_FRAMES + MPR_EVT_REPLY_FRAMES,
- sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
+ mpr_resize_queues(sc);
/*
* Initialize all Tail Queues
@@ -1146,11 +1181,11 @@ mpr_alloc_queues(struct mpr_softc *sc)
struct mpr_queue *q;
int nq, i;
- nq = MIN(sc->msi_msgs, mp_ncpus);
- sc->msi_msgs = nq;
+ nq = sc->msi_msgs;
mpr_dprint(sc, MPR_INIT|MPR_XINFO, "Allocating %d I/O queues\n", nq);
- sc->queues = malloc(sizeof(struct mpr_queue) * nq, M_MPR, M_NOWAIT|M_ZERO);
+ sc->queues = malloc(sizeof(struct mpr_queue) * nq, M_MPR,
+ M_NOWAIT|M_ZERO);
if (sc->queues == NULL)
return (ENOMEM);
@@ -1562,11 +1597,16 @@ mpr_get_tunables(struct mpr_softc *sc)
sc->mpr_debug = MPR_INFO | MPR_FAULT;
sc->disable_msix = 0;
sc->disable_msi = 0;
+ sc->max_msix = MPR_MSIX_MAX;
sc->max_chains = MPR_CHAIN_FRAMES;
sc->max_io_pages = MPR_MAXIO_PAGES;
sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD;
sc->spinup_wait_time = DEFAULT_SPINUP_WAIT;
sc->use_phynum = 1;
+ sc->max_reqframes = MPR_REQ_FRAMES;
+ sc->max_prireqframes = MPR_PRI_REQ_FRAMES;
+ sc->max_replyframes = MPR_REPLY_FRAMES;
+ sc->max_evtframes = MPR_EVT_REPLY_FRAMES;
/*
* Grab the global variables.
@@ -1574,11 +1614,16 @@ mpr_get_tunables(struct mpr_softc *sc)
TUNABLE_INT_FETCH("hw.mpr.debug_level", &sc->mpr_debug);
TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix);
TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi);
+ TUNABLE_INT_FETCH("hw.mpr.max_msix", &sc->max_msix);
TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains);
TUNABLE_INT_FETCH("hw.mpr.max_io_pages", &sc->max_io_pages);
TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu);
TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time);
TUNABLE_INT_FETCH("hw.mpr.use_phy_num", &sc->use_phynum);
+ TUNABLE_INT_FETCH("hw.mpr.max_reqframes", &sc->max_reqframes);
+ TUNABLE_INT_FETCH("hw.mpr.max_prireqframes", &sc->max_prireqframes);
+ TUNABLE_INT_FETCH("hw.mpr.max_replyframes", &sc->max_replyframes);
+ TUNABLE_INT_FETCH("hw.mpr.max_evtframes", &sc->max_evtframes);
/* Grab the unit-instance variables */
snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.debug_level",
@@ -1593,6 +1638,10 @@ mpr_get_tunables(struct mpr_softc *sc)
device_get_unit(sc->mpr_dev));
TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi);
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_msix",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_msix);
+
snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_chains",
device_get_unit(sc->mpr_dev));
TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
@@ -1617,6 +1666,22 @@ mpr_get_tunables(struct mpr_softc *sc)
snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.use_phy_num",
device_get_unit(sc->mpr_dev));
TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum);
+
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_reqframes",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_reqframes);
+
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_prireqframes",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_prireqframes);
+
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_replyframes",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_replyframes);
+
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_evtframes",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_evtframes);
}
static void
@@ -1658,8 +1723,28 @@ mpr_setup_sysctl(struct mpr_softc *sc)
"Disable the use of MSI-X interrupts");
SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
- OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0,
- "Disable the use of MSI interrupts");
+ OID_AUTO, "max_msix", CTLFLAG_RD, &sc->max_msix, 0,
+ "User-defined maximum number of MSIX queues");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "msix_msgs", CTLFLAG_RD, &sc->msi_msgs, 0,
+ "Negotiated number of MSIX queues");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "max_reqframes", CTLFLAG_RD, &sc->max_reqframes, 0,
+ "Total number of allocated request frames");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "max_prireqframes", CTLFLAG_RD, &sc->max_prireqframes, 0,
+ "Total number of allocated high priority request frames");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "max_replyframes", CTLFLAG_RD, &sc->max_replyframes, 0,
+ "Total number of allocated reply frames");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "max_evtframes", CTLFLAG_RD, &sc->max_evtframes, 0,
+ "Total number of event frames allocated");
SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "firmware_version", CTLFLAG_RW, sc->fw_version,
diff --git a/sys/dev/mpr/mpr_pci.c b/sys/dev/mpr/mpr_pci.c
index 0ac3e5ce8413..9430db5925de 100644
--- a/sys/dev/mpr/mpr_pci.c
+++ b/sys/dev/mpr/mpr_pci.c
@@ -262,23 +262,38 @@ mpr_pci_alloc_interrupts(struct mpr_softc *sc)
error = 0;
msgs = 0;
- if ((sc->disable_msix == 0) &&
- ((msgs = pci_msix_count(dev)) >= MPR_MSI_COUNT))
- error = mpr_alloc_msix(sc, MPR_MSI_COUNT);
- if ((error != 0) && (sc->disable_msi == 0) &&
- ((msgs = pci_msi_count(dev)) >= MPR_MSI_COUNT))
- error = mpr_alloc_msi(sc, MPR_MSI_COUNT);
- if (error != 0) {
+ if (sc->disable_msix == 0) {
+ msgs = pci_msix_count(dev);
+ mpr_dprint(sc, MPR_INIT, "Counted %d MSI-X messages\n", msgs);
+ msgs = min(msgs, sc->max_msix);
+ msgs = min(msgs, MPR_MSIX_MAX);
+ msgs = min(msgs, 1); /* XXX */
+ if (msgs != 0) {
+ mpr_dprint(sc, MPR_INIT, "Attempting to allocate %d MSI-X "
+ "messages\n", msgs);
+ error = mpr_alloc_msix(sc, msgs);
+ }
+ }
+ if (((error != 0) || (msgs == 0)) && (sc->disable_msi == 0)) {
+ msgs = pci_msi_count(dev);
+ mpr_dprint(sc, MPR_INIT, "Counted %d MSI messages\n", msgs);
+ msgs = min(msgs, MPR_MSI_MAX);
+ if (msgs != 0) {
+ mpr_dprint(sc, MPR_INIT, "Attempting to allocated %d MSI "
+ "messages\n", MPR_MSI_MAX);
+ error = mpr_alloc_msi(sc, MPR_MSI_MAX);
+ }
+ }
+ if ((error != 0) || (msgs == 0)) {
/*
* If neither MSI or MSI-X are available, assume legacy INTx.
* This also implies that there will be only 1 queue.
*/
+ mpr_dprint(sc, MPR_INIT, "Falling back to legacy INTx\n");
sc->mpr_flags |= MPR_FLAGS_INTX;
msgs = 1;
- } else {
+ } else
sc->mpr_flags |= MPR_FLAGS_MSI;
- msgs = MPR_MSI_COUNT; /* XXX */
- }
sc->msi_msgs = msgs;
mpr_dprint(sc, MPR_INIT, "Allocated %d interrupts\n", msgs);
@@ -318,6 +333,7 @@ mpr_pci_setup_interrupts(struct mpr_softc *sc)
if (q->irq == NULL) {
mpr_dprint(sc, MPR_ERROR|MPR_INIT,
"Cannot allocate interrupt RID %d\n", rid);
+ sc->msi_msgs = i;
break;
}
error = bus_setup_intr(dev, q->irq,
@@ -326,6 +342,7 @@ mpr_pci_setup_interrupts(struct mpr_softc *sc)
if (error) {
mpr_dprint(sc, MPR_ERROR|MPR_INIT,
"Cannot setup interrupt RID %d\n", rid);
+ sc->msi_msgs = i;
break;
}
}
diff --git a/sys/dev/mpr/mpr_sas.c b/sys/dev/mpr/mpr_sas.c
index c646eb1743d2..e683e508db7d 100644
--- a/sys/dev/mpr/mpr_sas.c
+++ b/sys/dev/mpr/mpr_sas.c
@@ -924,6 +924,9 @@ mpr_detach_sas(struct mpr_softc *sc)
/* Make sure CAM doesn't wedge if we had to bail out early. */
mpr_lock(sc);
+ while (sassc->startup_refcount != 0)
+ mprsas_startup_decrement(sassc);
+
/* Deregister our async handler */
if (sassc->path != NULL) {
xpt_register_async(0, mprsas_async, sc, sassc->path);
diff --git a/sys/dev/mpr/mprvar.h b/sys/dev/mpr/mprvar.h
index a33c2a0bf16c..0e97d6fefca4 100644
--- a/sys/dev/mpr/mprvar.h
+++ b/sys/dev/mpr/mprvar.h
@@ -37,13 +37,15 @@
#define MPR_DB_MAX_WAIT 2500
-#define MPR_REQ_FRAMES 1024
+#define MPR_REQ_FRAMES 2048
+#define MPR_PRI_REQ_FRAMES 128
#define MPR_EVT_REPLY_FRAMES 32
#define MPR_REPLY_FRAMES MPR_REQ_FRAMES
#define MPR_CHAIN_FRAMES 2048
#define MPR_MAXIO_PAGES (-1)
#define MPR_SENSE_LEN SSD_FULL_SIZE
-#define MPR_MSI_COUNT 1
+#define MPR_MSI_MAX 1
+#define MPR_MSIX_MAX 96
#define MPR_SGE64_SIZE 12
#define MPR_SGE32_SIZE 8
#define MPR_SGC_SIZE 8
@@ -296,8 +298,6 @@ struct mpr_softc {
#define MPR_FLAGS_GEN35_IOC (1 << 6)
#define MPR_FLAGS_REALLOCATED (1 << 7)
u_int mpr_debug;
- u_int disable_msix;
- u_int disable_msi;
int msi_msgs;
u_int atomic_desc_capable;
int tm_cmds_active;
@@ -446,7 +446,16 @@ struct mpr_softc {
uint32_t SSU_refcount;
uint8_t SSU_started;
+ /* Configuration tunables */
+ u_int disable_msix;
+ u_int disable_msi;
+ u_int max_msix;
+ u_int max_reqframes;
+ u_int max_prireqframes;
+ u_int max_replyframes;
+ u_int max_evtframes;
char exclude_ids[80];
+
struct timeval lastfail;
};