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;
 }

Reply via email to