Module Name: src Committed By: christos Date: Tue Oct 27 16:03:04 UTC 2015
Modified Files: src/sys/dev/pci: ld_virtio.c Log Message: - Print the negotiated feature bits - Define a constant for the minimum number of segments and use that. - Remove unused sc_lock - Use single variables instead of arrays of 1 element - To the transfer size and segment size negotiation more correctly - Make vr_bp NULL when unused. - Add missing abort calls To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/dev/pci/ld_virtio.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/ld_virtio.c diff -u src/sys/dev/pci/ld_virtio.c:1.8 src/sys/dev/pci/ld_virtio.c:1.9 --- src/sys/dev/pci/ld_virtio.c:1.8 Tue May 5 06:56:13 2015 +++ src/sys/dev/pci/ld_virtio.c Tue Oct 27 12:03:04 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: ld_virtio.c,v 1.8 2015/05/05 10:56:13 ozaki-r Exp $ */ +/* $NetBSD: ld_virtio.c,v 1.9 2015/10/27 16:03:04 christos Exp $ */ /* * Copyright (c) 2010 Minoura Makoto. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.8 2015/05/05 10:56:13 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.9 2015/10/27 16:03:04 christos Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -67,6 +67,23 @@ __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c, #define VIRTIO_BLK_F_SCSI (1<<7) #define VIRTIO_BLK_F_FLUSH (1<<9) +/* + * Each block request uses at least two segments - one for the header + * and one for the status. +*/ +#define VIRTIO_BLK_MIN_SEGMENTS 2 + +#define VIRTIO_BLK_FLAG_BITS \ + VIRTIO_COMMON_FLAG_BITS \ + "\x0a""FLUSH" \ + "\x08""SCSI" \ + "\x07""BLK_SIZE" \ + "\x06""RO" \ + "\x05""GEOMETRY" \ + "\x03""SEG_MAX" \ + "\x02""SIZE_MAX" \ + "\x01""BARRIER" + /* Command */ #define VIRTIO_BLK_T_IN 0 #define VIRTIO_BLK_T_OUT 1 @@ -101,12 +118,10 @@ struct ld_virtio_softc { device_t sc_dev; struct virtio_softc *sc_virtio; - struct virtqueue sc_vq[1]; + struct virtqueue sc_vq; struct virtio_blk_req *sc_reqs; - bus_dma_segment_t sc_reqs_segs[1]; - - kmutex_t sc_lock; + bus_dma_segment_t sc_reqs_seg; int sc_readonly; }; @@ -142,7 +157,7 @@ ld_virtio_alloc_reqs(struct ld_virtio_so allocsize = sizeof(struct virtio_blk_req) * qsize; r = bus_dmamem_alloc(sc->sc_virtio->sc_dmat, allocsize, 0, 0, - &sc->sc_reqs_segs[0], 1, &rsegs, BUS_DMA_NOWAIT); + &sc->sc_reqs_seg, 1, &rsegs, BUS_DMA_NOWAIT); if (r != 0) { aprint_error_dev(sc->sc_dev, "DMA memory allocation failed, size %d, " @@ -150,7 +165,7 @@ ld_virtio_alloc_reqs(struct ld_virtio_so goto err_none; } r = bus_dmamem_map(sc->sc_virtio->sc_dmat, - &sc->sc_reqs_segs[0], 1, allocsize, + &sc->sc_reqs_seg, 1, allocsize, &vaddr, BUS_DMA_NOWAIT); if (r != 0) { aprint_error_dev(sc->sc_dev, @@ -187,7 +202,8 @@ ld_virtio_alloc_reqs(struct ld_virtio_so } r = bus_dmamap_create(sc->sc_virtio->sc_dmat, ld->sc_maxxfer, - (ld->sc_maxxfer / NBPG) + 2, + (ld->sc_maxxfer / NBPG) + + VIRTIO_BLK_MIN_SEGMENTS, ld->sc_maxxfer, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, @@ -217,7 +233,7 @@ err_reqs: } bus_dmamem_unmap(sc->sc_virtio->sc_dmat, sc->sc_reqs, allocsize); err_dmamem_alloc: - bus_dmamem_free(sc->sc_virtio->sc_dmat, &sc->sc_reqs_segs[0], 1); + bus_dmamem_free(sc->sc_virtio->sc_dmat, &sc->sc_reqs_seg, 1); err_none: return -1; } @@ -229,7 +245,8 @@ ld_virtio_attach(device_t parent, device struct ld_softc *ld = &sc->sc_ld; struct virtio_softc *vsc = device_private(parent); uint32_t features; - int qsize, maxxfersize; + char buf[256]; + int qsize, maxxfersize, maxnsegs; if (vsc->sc_child != NULL) { aprint_normal(": child already attached for %s; " @@ -237,15 +254,13 @@ ld_virtio_attach(device_t parent, device device_xname(parent)); return; } - aprint_normal("\n"); - aprint_naive("\n"); sc->sc_dev = self; sc->sc_virtio = vsc; vsc->sc_child = self; vsc->sc_ipl = IPL_BIO; - vsc->sc_vqs = &sc->sc_vq[0]; + vsc->sc_vqs = &sc->sc_vq; vsc->sc_nvqs = 1; vsc->sc_config_change = NULL; vsc->sc_intrhand = virtio_vq_intr; @@ -262,29 +277,57 @@ ld_virtio_attach(device_t parent, device else sc->sc_readonly = 0; - ld->sc_secsize = 512; + snprintb(buf, sizeof(buf), VIRTIO_BLK_FLAG_BITS, features); + aprint_normal(": Features: %s\n", buf); + aprint_naive("\n"); if (features & VIRTIO_BLK_F_BLK_SIZE) { ld->sc_secsize = virtio_read_device_config_4(vsc, VIRTIO_BLK_CONFIG_BLK_SIZE); - } - maxxfersize = MAXPHYS; -#if 0 /* At least genfs_io assumes maxxfer == MAXPHYS. */ - if (features & VIRTIO_BLK_F_SEG_MAX) { + } else + ld->sc_secsize = 512; + + /* At least genfs_io assumes maxxfer == MAXPHYS. */ + if (features & VIRTIO_BLK_F_SIZE_MAX) { maxxfersize = virtio_read_device_config_4(vsc, - VIRTIO_BLK_CONFIG_SEG_MAX) - * ld->sc_secsize; - if (maxxfersize > MAXPHYS) + VIRTIO_BLK_CONFIG_SIZE_MAX); + if (maxxfersize < MAXPHYS) { + aprint_error_dev(sc->sc_dev, + "Too small SIZE_MAX %dK minimum is %dK\n", + maxxfersize / 1024, MAXPHYS / 1024); + // goto err; maxxfersize = MAXPHYS; - } -#endif + } else if (maxxfersize > MAXPHYS) { + aprint_normal_dev(sc->sc_dev, + "Clip SEG_MAX from %dK to %dK\n", + maxxfersize / 1024, + MAXPHYS / 1024); + maxxfersize = MAXPHYS; + } + } else + maxxfersize = MAXPHYS; + + if (features & VIRTIO_BLK_F_SEG_MAX) { + maxnsegs = virtio_read_device_config_4(vsc, + VIRTIO_BLK_CONFIG_SEG_MAX); + if (maxnsegs < VIRTIO_BLK_MIN_SEGMENTS) { + aprint_error_dev(sc->sc_dev, + "Too small SEG_MAX %d minimum is %d\n", + maxnsegs, VIRTIO_BLK_MIN_SEGMENTS); + maxnsegs = maxxfersize / NBPG; + // goto err; + } + } else + maxnsegs = maxxfersize / NBPG; - if (virtio_alloc_vq(vsc, &sc->sc_vq[0], 0, - maxxfersize, maxxfersize / NBPG + 2, - "I/O request") != 0) { + /* 2 for the minimum size */ + maxnsegs += VIRTIO_BLK_MIN_SEGMENTS; + + if (virtio_alloc_vq(vsc, &sc->sc_vq, 0, maxxfersize, maxnsegs, + "I/O request") != 0) { goto err; } - qsize = sc->sc_vq[0].vq_num; - sc->sc_vq[0].vq_done = ld_virtio_vq_done; + qsize = sc->sc_vq.vq_num; + sc->sc_vq.vq_done = ld_virtio_vq_done; ld->sc_dv = self; ld->sc_secperunit = virtio_read_device_config_8(vsc, @@ -303,8 +346,6 @@ ld_virtio_attach(device_t parent, device if (ld_virtio_alloc_reqs(sc, qsize) < 0) goto err; - mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO); - ld->sc_dump = ld_virtio_dump; ld->sc_flush = NULL; ld->sc_start = ld_virtio_start; @@ -325,7 +366,7 @@ ld_virtio_start(struct ld_softc *ld, str /* splbio */ struct ld_virtio_softc *sc = device_private(ld->sc_dv); struct virtio_softc *vsc = sc->sc_virtio; - struct virtqueue *vq = &sc->sc_vq[0]; + struct virtqueue *vq = &sc->sc_vq; struct virtio_blk_req *vr; int r; int isread = (bp->b_flags & B_READ); @@ -337,16 +378,25 @@ ld_virtio_start(struct ld_softc *ld, str r = virtio_enqueue_prep(vsc, vq, &slot); if (r != 0) return r; + vr = &sc->sc_reqs[slot]; + KASSERT(vr->vr_bp == NULL); + r = bus_dmamap_load(vsc->sc_dmat, vr->vr_payload, bp->b_data, bp->b_bcount, NULL, ((isread?BUS_DMA_READ:BUS_DMA_WRITE) |BUS_DMA_NOWAIT)); - if (r != 0) + if (r != 0) { + aprint_error_dev(sc->sc_dev, + "payload dmamap failed, error code %d\n", r); + virtio_enqueue_abort(vsc, vq, slot); return r; + } - r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + 2); + r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + + VIRTIO_BLK_MIN_SEGMENTS); if (r != 0) { + virtio_enqueue_abort(vsc, vq, slot); bus_dmamap_unload(vsc->sc_dmat, vr->vr_payload); return r; } @@ -387,6 +437,8 @@ ld_virtio_vq_done1(struct ld_virtio_soft struct virtio_blk_req *vr = &sc->sc_reqs[slot]; struct buf *bp = vr->vr_bp; + vr->vr_bp = NULL; + bus_dmamap_sync(vsc->sc_dmat, vr->vr_cmdsts, 0, sizeof(struct virtio_blk_req_hdr), BUS_DMASYNC_POSTWRITE); @@ -433,7 +485,7 @@ ld_virtio_dump(struct ld_softc *ld, void { struct ld_virtio_softc *sc = device_private(ld->sc_dv); struct virtio_softc *vsc = sc->sc_virtio; - struct virtqueue *vq = &sc->sc_vq[0]; + struct virtqueue *vq = &sc->sc_vq; struct virtio_blk_req *vr; int slot, r; @@ -458,7 +510,8 @@ ld_virtio_dump(struct ld_softc *ld, void if (r != 0) return r; - r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + 2); + r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + + VIRTIO_BLK_MIN_SEGMENTS); if (r != 0) { bus_dmamap_unload(vsc->sc_dmat, vr->vr_payload); return r; @@ -530,12 +583,12 @@ ld_virtio_detach(device_t self, int flag bus_dma_tag_t dmat = sc->sc_virtio->sc_dmat; int r, i, qsize; - qsize = sc->sc_vq[0].vq_num; + qsize = sc->sc_vq.vq_num; r = ldbegindetach(ld, flags); if (r != 0) return r; virtio_reset(sc->sc_virtio); - virtio_free_vq(sc->sc_virtio, &sc->sc_vq[0]); + virtio_free_vq(sc->sc_virtio, &sc->sc_vq); for (i = 0; i < qsize; i++) { bus_dmamap_destroy(dmat, @@ -545,7 +598,7 @@ ld_virtio_detach(device_t self, int flag } bus_dmamem_unmap(dmat, sc->sc_reqs, sizeof(struct virtio_blk_req) * qsize); - bus_dmamem_free(dmat, &sc->sc_reqs_segs[0], 1); + bus_dmamem_free(dmat, &sc->sc_reqs_seg, 1); ldenddetach(ld);