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) {

Reply via email to