Module Name: src Committed By: jdolecek Date: Tue Mar 7 22:03:04 UTC 2017
Modified Files: src/sys/dev/pci: vioscsi.c Log Message: allocate bus dma maps during attachment, rather than creating and destroying them for each request; besides being faster, bus_dmamap_destroy() is not safe to be called from interrupt context adresses PR kern/52034 by Benny Siegert To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/dev/pci/vioscsi.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/pci/vioscsi.c diff -u src/sys/dev/pci/vioscsi.c:1.8 src/sys/dev/pci/vioscsi.c:1.9 --- src/sys/dev/pci/vioscsi.c:1.8 Tue Oct 4 18:23:24 2016 +++ src/sys/dev/pci/vioscsi.c Tue Mar 7 22:03:04 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: vioscsi.c,v 1.8 2016/10/04 18:23:24 jdolecek Exp $ */ +/* $NetBSD: vioscsi.c,v 1.9 2017/03/07 22:03:04 jdolecek Exp $ */ /* $OpenBSD: vioscsi.c,v 1.3 2015/03/14 03:38:49 jsg Exp $ */ /* @@ -18,7 +18,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vioscsi.c,v 1.8 2016/10/04 18:23:24 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vioscsi.c,v 1.9 2017/03/07 22:03:04 jdolecek Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -58,6 +58,7 @@ struct vioscsi_softc { struct virtqueue sc_vqs[3]; struct vioscsi_req *sc_reqs; + int sc_nreqs; bus_dma_segment_t sc_reqs_segs[1]; u_int32_t sc_seg_max; @@ -470,47 +471,17 @@ vioscsi_req_get(struct vioscsi_softc *sc if ((r = virtio_enqueue_prep(vsc, vq, &slot)) != 0) { DPRINTF(("%s: virtio_enqueue_get error %d\n", __func__, r)); - goto err1; + return NULL; } + KASSERT(slot < sc->sc_nreqs); vr = &sc->sc_reqs[slot]; vr->vr_req.id = slot; vr->vr_req.task_attr = VIRTIO_SCSI_S_SIMPLE; - r = bus_dmamap_create(vsc->sc_dmat, - offsetof(struct vioscsi_req, vr_xs), 1, - offsetof(struct vioscsi_req, vr_xs), 0, - BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &vr->vr_control); - if (r != 0) { - DPRINTF(("%s: bus_dmamap_create xs error %d\n", __func__, r)); - goto err2; - } - r = bus_dmamap_create(vsc->sc_dmat, MAXPHYS, sc->sc_seg_max, - MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &vr->vr_data); - if (r != 0) { - DPRINTF(("%s: bus_dmamap_create data error %d\n", __func__, r)); - goto err3; - } - r = bus_dmamap_load(vsc->sc_dmat, vr->vr_control, - vr, offsetof(struct vioscsi_req, vr_xs), NULL, - BUS_DMA_NOWAIT); - if (r != 0) { - DPRINTF(("%s: bus_dmamap_create ctrl error %d\n", __func__, r)); - goto err4; - } - DPRINTF(("%s: %p, %d\n", __func__, vr, slot)); return vr; - -err4: - bus_dmamap_destroy(vsc->sc_dmat, vr->vr_data); -err3: - bus_dmamap_destroy(vsc->sc_dmat, vr->vr_control); -err2: - virtio_enqueue_abort(vsc, vq, slot); -err1: - return NULL; } static void @@ -522,8 +493,7 @@ vioscsi_req_put(struct vioscsi_softc *sc DPRINTF(("%s: %p, %d\n", __func__, vr, slot)); - bus_dmamap_destroy(vsc->sc_dmat, vr->vr_control); - bus_dmamap_destroy(vsc->sc_dmat, vr->vr_data); + bus_dmamap_unload(vsc->sc_dmat, vr->vr_data); virtio_dequeue_commit(vsc, vq, slot); } @@ -533,8 +503,9 @@ vioscsi_alloc_reqs(struct vioscsi_softc int qsize, uint32_t seg_max) { size_t allocsize; - int r, rsegs; + int r, rsegs, slot; void *vaddr; + struct vioscsi_req *vr; allocsize = qsize * sizeof(struct vioscsi_req); r = bus_dmamem_alloc(vsc->sc_dmat, allocsize, 0, 0, @@ -543,7 +514,7 @@ vioscsi_alloc_reqs(struct vioscsi_softc aprint_error_dev(sc->sc_dev, "%s: bus_dmamem_alloc, size %zu, error %d\n", __func__, allocsize, r); - return 1; + return r; } r = bus_dmamem_map(vsc->sc_dmat, &sc->sc_reqs_segs[0], 1, allocsize, &vaddr, BUS_DMA_NOWAIT); @@ -551,9 +522,68 @@ vioscsi_alloc_reqs(struct vioscsi_softc aprint_error_dev(sc->sc_dev, "%s: bus_dmamem_map failed, error %d\n", __func__, r); bus_dmamem_free(vsc->sc_dmat, &sc->sc_reqs_segs[0], 1); - return 1; + return r; } - sc->sc_reqs = vaddr; memset(vaddr, 0, allocsize); + + sc->sc_reqs = vaddr; + sc->sc_nreqs = qsize; + + /* Prepare maps for the requests */ + for (slot=0; slot < qsize; slot++) { + vr = &sc->sc_reqs[slot]; + + r = bus_dmamap_create(vsc->sc_dmat, + offsetof(struct vioscsi_req, vr_xs), 1, + offsetof(struct vioscsi_req, vr_xs), 0, + BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &vr->vr_control); + if (r != 0) { + aprint_error_dev(sc->sc_dev, + "%s: bus_dmamem_create failed, error %d\n", + __func__, r); + goto cleanup; + } + + r = bus_dmamap_create(vsc->sc_dmat, MAXPHYS, sc->sc_seg_max, + MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &vr->vr_data); + if (r != 0) { + aprint_error_dev(sc->sc_dev, + "%s: bus_dmamem_map failed, error %d\n", + __func__, r); + goto cleanup; + } + + r = bus_dmamap_load(vsc->sc_dmat, vr->vr_control, + vr, offsetof(struct vioscsi_req, vr_xs), NULL, + BUS_DMA_NOWAIT); + if (r != 0) { + aprint_error_dev(sc->sc_dev, + "%s: bus_dmamap_create ctrl error %d\n", + __func__, r); + goto cleanup; + } + } + return 0; + +cleanup: + for (; slot > 0; slot--) { + vr = &sc->sc_reqs[slot]; + + if (vr->vr_control) { + /* this will also unload the mapping if loaded */ + bus_dmamap_destroy(vsc->sc_dmat, vr->vr_control); + vr->vr_control = NULL; + } + + if (vr->vr_data) { + bus_dmamap_destroy(vsc->sc_dmat, vr->vr_data); + vr->vr_data = NULL; + } + } + + bus_dmamem_unmap(vsc->sc_dmat, vaddr, allocsize); + bus_dmamem_free(vsc->sc_dmat, &sc->sc_reqs_segs[0], 1); + + return r; }