Module Name: src
Committed By: jdolecek
Date: Wed Oct 19 19:31:23 UTC 2016
Modified Files:
src/sys/dev/ic: nvme.c nvmevar.h
src/sys/dev/pci: nvme_pci.c
Log Message:
follow advice of spec and block interrupts via INTMS/INTMC for intx handler;
this also makes it possible to offload the actual interrupt processing to
softintr
handler, similar as for MSI/MSI-X
To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/ic/nvme.c
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/ic/nvmevar.h
cvs rdiff -u -r1.15 -r1.16 src/sys/dev/pci/nvme_pci.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ic/nvme.c
diff -u src/sys/dev/ic/nvme.c:1.16 src/sys/dev/ic/nvme.c:1.17
--- src/sys/dev/ic/nvme.c:1.16 Tue Oct 18 07:48:05 2016
+++ src/sys/dev/ic/nvme.c Wed Oct 19 19:31:23 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: nvme.c,v 1.16 2016/10/18 07:48:05 nonaka Exp $ */
+/* $NetBSD: nvme.c,v 1.17 2016/10/19 19:31:23 jdolecek Exp $ */
/* $OpenBSD: nvme.c,v 1.49 2016/04/18 05:59:50 dlg Exp $ */
/*
@@ -18,7 +18,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.16 2016/10/18 07:48:05 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.17 2016/10/19 19:31:23 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -1420,19 +1420,38 @@ int
nvme_intr(void *xsc)
{
struct nvme_softc *sc = xsc;
- int rv = 0;
/*
* INTx is level triggered, controller deasserts the interrupt only
* when we advance command queue head via write to the doorbell.
+ * Tell the controller to block the interrupts while we process
+ * the queue(s).
*/
- if (nvme_q_complete(sc, sc->sc_admin_q))
- rv = 1;
+ nvme_write4(sc, NVME_INTMS, 1);
+
+ softint_schedule(sc->sc_softih[0]);
+
+ /* don't know, might not have been for us */
+ return 1;
+}
+
+void
+nvme_softintr_intx(void *xq)
+{
+ struct nvme_queue *q = xq;
+ struct nvme_softc *sc = q->q_sc;
+
+ nvme_q_complete(sc, sc->sc_admin_q);
if (sc->sc_q != NULL)
- if (nvme_q_complete(sc, sc->sc_q[0]))
- rv = 1;
+ nvme_q_complete(sc, sc->sc_q[0]);
- return rv;
+ /*
+ * Processing done, tell controller to issue interrupts again. There
+ * is no race, as NVMe spec requires the controller to maintain state,
+ * and assert the interrupt whenever there are unacknowledged
+ * completion queue entries.
+ */
+ nvme_write4(sc, NVME_INTMC, 1);
}
int
@@ -1443,7 +1462,10 @@ nvme_intr_msi(void *xq)
KASSERT(q && q->q_sc && q->q_sc->sc_softih
&& q->q_sc->sc_softih[q->q_id]);
- /* MSI are edge triggered, so can handover processing to softint */
+ /*
+ * MSI/MSI-X are edge triggered, so can handover processing to softint
+ * without masking the interrupt.
+ */
softint_schedule(q->q_sc->sc_softih[q->q_id]);
return 1;
Index: src/sys/dev/ic/nvmevar.h
diff -u src/sys/dev/ic/nvmevar.h:1.6 src/sys/dev/ic/nvmevar.h:1.7
--- src/sys/dev/ic/nvmevar.h:1.6 Tue Sep 27 03:33:32 2016
+++ src/sys/dev/ic/nvmevar.h Wed Oct 19 19:31:23 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: nvmevar.h,v 1.6 2016/09/27 03:33:32 pgoyette Exp $ */
+/* $NetBSD: nvmevar.h,v 1.7 2016/10/19 19:31:23 jdolecek Exp $ */
/* $OpenBSD: nvmevar.h,v 1.8 2016/04/14 11:18:32 dlg Exp $ */
/*
@@ -151,6 +151,7 @@ int nvme_detach(struct nvme_softc *, int
int nvme_rescan(device_t, const char *, const int *);
void nvme_childdet(device_t, device_t);
int nvme_intr(void *);
+void nvme_softintr_intx(void *);
int nvme_intr_msi(void *);
void nvme_softintr_msi(void *);
Index: src/sys/dev/pci/nvme_pci.c
diff -u src/sys/dev/pci/nvme_pci.c:1.15 src/sys/dev/pci/nvme_pci.c:1.16
--- src/sys/dev/pci/nvme_pci.c:1.15 Tue Sep 27 03:33:32 2016
+++ src/sys/dev/pci/nvme_pci.c Wed Oct 19 19:31:23 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: nvme_pci.c,v 1.15 2016/09/27 03:33:32 pgoyette Exp $ */
+/* $NetBSD: nvme_pci.c,v 1.16 2016/10/19 19:31:23 jdolecek Exp $ */
/* $OpenBSD: nvme_pci.c,v 1.3 2016/04/14 11:18:32 dlg Exp $ */
/*
@@ -43,7 +43,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvme_pci.c,v 1.15 2016/09/27 03:33:32 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvme_pci.c,v 1.16 2016/10/19 19:31:23 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -193,14 +193,12 @@ nvme_pci_attach(device_t parent, device_
goto intr_release;
}
- if (sc->sc_use_mq) {
- sc->sc_softih = kmem_zalloc(
- sizeof(*sc->sc_softih) * psc->psc_nintrs, KM_SLEEP);
- if (sc->sc_softih == NULL) {
- aprint_error_dev(self,
- "unable to allocate softih memory\n");
- goto intr_free;
- }
+ sc->sc_softih = kmem_zalloc(
+ sizeof(*sc->sc_softih) * psc->psc_nintrs, KM_SLEEP);
+ if (sc->sc_softih == NULL) {
+ aprint_error_dev(self,
+ "unable to allocate softih memory\n");
+ goto intr_free;
}
if (nvme_attach(sc) != 0) {
@@ -215,10 +213,7 @@ nvme_pci_attach(device_t parent, device_
return;
softintr_free:
- if (sc->sc_softih) {
- kmem_free(sc->sc_softih,
- sizeof(*sc->sc_softih) * psc->psc_nintrs);
- }
+ kmem_free(sc->sc_softih, sizeof(*sc->sc_softih) * psc->psc_nintrs);
intr_free:
kmem_free(sc->sc_ih, sizeof(*sc->sc_ih) * psc->psc_nintrs);
sc->sc_nq = 0;
@@ -251,11 +246,9 @@ nvme_pci_detach(device_t self, int flags
if (error)
return error;
- if (sc->sc_softih) {
- kmem_free(sc->sc_softih,
- sizeof(*sc->sc_softih) * psc->psc_nintrs);
- sc->sc_softih = NULL;
- }
+ kmem_free(sc->sc_softih, sizeof(*sc->sc_softih) * psc->psc_nintrs);
+ sc->sc_softih = NULL;
+
kmem_free(sc->sc_ih, sizeof(*sc->sc_ih) * psc->psc_nintrs);
pci_intr_release(psc->psc_pc, psc->psc_intrs, psc->psc_nintrs);
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
@@ -271,6 +264,7 @@ nvme_pci_intr_establish(struct nvme_soft
char intrbuf[PCI_INTRSTR_LEN];
const char *intrstr = NULL;
int (*ih_func)(void *);
+ void (*ih_func_soft)(void *);
void *ih_arg;
#ifdef __HAVE_PCI_MSI_MSIX
int error;
@@ -291,6 +285,7 @@ nvme_pci_intr_establish(struct nvme_soft
device_xname(sc->sc_dev));
ih_arg = sc;
ih_func = nvme_intr;
+ ih_func_soft = nvme_softintr_intx;
#ifdef __HAVE_PCI_MSI_MSIX
}
else {
@@ -303,6 +298,7 @@ nvme_pci_intr_establish(struct nvme_soft
}
ih_arg = q;
ih_func = nvme_intr_msi;
+ ih_func_soft = nvme_softintr_msi;
}
#endif /* __HAVE_PCI_MSI_MSIX */
@@ -315,22 +311,20 @@ nvme_pci_intr_establish(struct nvme_soft
return 1;
}
- /* if MSI, establish also the software interrupt */
- if (sc->sc_softih) {
- sc->sc_softih[qid] = softint_establish(
- SOFTINT_BIO|(nvme_pci_mpsafe ? SOFTINT_MPSAFE : 0),
- nvme_softintr_msi, q);
- if (sc->sc_softih[qid] == NULL) {
- pci_intr_disestablish(psc->psc_pc, sc->sc_ih[qid]);
- sc->sc_ih[qid] = NULL;
-
- aprint_error_dev(sc->sc_dev,
- "unable to establish %s soft interrupt\n",
- intr_xname);
- return 1;
- }
+ /* establish also the software interrupt */
+ sc->sc_softih[qid] = softint_establish(
+ SOFTINT_BIO|(nvme_pci_mpsafe ? SOFTINT_MPSAFE : 0),
+ ih_func_soft, q);
+ if (sc->sc_softih[qid] == NULL) {
+ pci_intr_disestablish(psc->psc_pc, sc->sc_ih[qid]);
+ sc->sc_ih[qid] = NULL;
+
+ aprint_error_dev(sc->sc_dev,
+ "unable to establish %s soft interrupt\n",
+ intr_xname);
+ return 1;
}
-
+
intrstr = pci_intr_string(psc->psc_pc, psc->psc_intrs[qid], intrbuf,
sizeof(intrbuf));
if (!sc->sc_use_mq) {