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