1/*- 2 * Copyright (c) 2013, Bryan Venteicher <bryanv@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27/* Driver for VirtIO entropy device. */ 28 29#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2013, Bryan Venteicher <bryanv@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27/* Driver for VirtIO entropy device. */ 28 29#include <sys/cdefs.h>
|
30__FBSDID("$FreeBSD: head/sys/dev/virtio/random/virtio_random.c 260847 2014-01-18 06:14:38Z bryanv $");
| 30__FBSDID("$FreeBSD: stable/10/sys/dev/virtio/random/virtio_random.c 268933 2014-07-21 00:21:56Z jhb $");
|
31 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/module.h> 35#include <sys/sglist.h> 36#include <sys/callout.h> 37#include <sys/random.h> 38 39#include <machine/bus.h> 40#include <machine/resource.h> 41#include <sys/bus.h> 42 43#include <dev/virtio/virtio.h> 44#include <dev/virtio/virtqueue.h> 45 46struct vtrnd_softc { 47 device_t vtrnd_dev; 48 uint64_t vtrnd_features; 49 struct callout vtrnd_callout; 50 struct virtqueue *vtrnd_vq; 51}; 52 53static int vtrnd_modevent(module_t, int, void *); 54 55static int vtrnd_probe(device_t); 56static int vtrnd_attach(device_t); 57static int vtrnd_detach(device_t); 58 59static void vtrnd_negotiate_features(struct vtrnd_softc *); 60static int vtrnd_alloc_virtqueue(struct vtrnd_softc *); 61static void vtrnd_harvest(struct vtrnd_softc *); 62static void vtrnd_timer(void *); 63 64#define VTRND_FEATURES 0 65 66static struct virtio_feature_desc vtrnd_feature_desc[] = { 67 { 0, NULL } 68}; 69 70static device_method_t vtrnd_methods[] = { 71 /* Device methods. */ 72 DEVMETHOD(device_probe, vtrnd_probe), 73 DEVMETHOD(device_attach, vtrnd_attach), 74 DEVMETHOD(device_detach, vtrnd_detach), 75 76 DEVMETHOD_END 77}; 78 79static driver_t vtrnd_driver = { 80 "vtrnd", 81 vtrnd_methods, 82 sizeof(struct vtrnd_softc) 83}; 84static devclass_t vtrnd_devclass; 85 86DRIVER_MODULE(virtio_random, virtio_pci, vtrnd_driver, vtrnd_devclass, 87 vtrnd_modevent, 0); 88MODULE_VERSION(virtio_random, 1); 89MODULE_DEPEND(virtio_random, virtio, 1, 1, 1); 90 91static int 92vtrnd_modevent(module_t mod, int type, void *unused) 93{ 94 int error; 95 96 switch (type) { 97 case MOD_LOAD: 98 case MOD_QUIESCE: 99 case MOD_UNLOAD: 100 case MOD_SHUTDOWN: 101 error = 0; 102 break; 103 default: 104 error = EOPNOTSUPP; 105 break; 106 } 107 108 return (error); 109} 110 111static int 112vtrnd_probe(device_t dev) 113{ 114 115 if (virtio_get_device_type(dev) != VIRTIO_ID_ENTROPY) 116 return (ENXIO); 117 118 device_set_desc(dev, "VirtIO Entropy Adapter"); 119 120 return (BUS_PROBE_DEFAULT); 121} 122 123static int 124vtrnd_attach(device_t dev) 125{ 126 struct vtrnd_softc *sc; 127 int error; 128 129 sc = device_get_softc(dev); 130 sc->vtrnd_dev = dev; 131 132 callout_init(&sc->vtrnd_callout, CALLOUT_MPSAFE); 133 134 virtio_set_feature_desc(dev, vtrnd_feature_desc); 135 vtrnd_negotiate_features(sc); 136 137 error = vtrnd_alloc_virtqueue(sc); 138 if (error) { 139 device_printf(dev, "cannot allocate virtqueue\n"); 140 goto fail; 141 } 142 143 callout_reset(&sc->vtrnd_callout, 5 * hz, vtrnd_timer, sc); 144 145fail: 146 if (error) 147 vtrnd_detach(dev); 148 149 return (error); 150} 151 152static int 153vtrnd_detach(device_t dev) 154{ 155 struct vtrnd_softc *sc; 156 157 sc = device_get_softc(dev); 158
| 31 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/module.h> 35#include <sys/sglist.h> 36#include <sys/callout.h> 37#include <sys/random.h> 38 39#include <machine/bus.h> 40#include <machine/resource.h> 41#include <sys/bus.h> 42 43#include <dev/virtio/virtio.h> 44#include <dev/virtio/virtqueue.h> 45 46struct vtrnd_softc { 47 device_t vtrnd_dev; 48 uint64_t vtrnd_features; 49 struct callout vtrnd_callout; 50 struct virtqueue *vtrnd_vq; 51}; 52 53static int vtrnd_modevent(module_t, int, void *); 54 55static int vtrnd_probe(device_t); 56static int vtrnd_attach(device_t); 57static int vtrnd_detach(device_t); 58 59static void vtrnd_negotiate_features(struct vtrnd_softc *); 60static int vtrnd_alloc_virtqueue(struct vtrnd_softc *); 61static void vtrnd_harvest(struct vtrnd_softc *); 62static void vtrnd_timer(void *); 63 64#define VTRND_FEATURES 0 65 66static struct virtio_feature_desc vtrnd_feature_desc[] = { 67 { 0, NULL } 68}; 69 70static device_method_t vtrnd_methods[] = { 71 /* Device methods. */ 72 DEVMETHOD(device_probe, vtrnd_probe), 73 DEVMETHOD(device_attach, vtrnd_attach), 74 DEVMETHOD(device_detach, vtrnd_detach), 75 76 DEVMETHOD_END 77}; 78 79static driver_t vtrnd_driver = { 80 "vtrnd", 81 vtrnd_methods, 82 sizeof(struct vtrnd_softc) 83}; 84static devclass_t vtrnd_devclass; 85 86DRIVER_MODULE(virtio_random, virtio_pci, vtrnd_driver, vtrnd_devclass, 87 vtrnd_modevent, 0); 88MODULE_VERSION(virtio_random, 1); 89MODULE_DEPEND(virtio_random, virtio, 1, 1, 1); 90 91static int 92vtrnd_modevent(module_t mod, int type, void *unused) 93{ 94 int error; 95 96 switch (type) { 97 case MOD_LOAD: 98 case MOD_QUIESCE: 99 case MOD_UNLOAD: 100 case MOD_SHUTDOWN: 101 error = 0; 102 break; 103 default: 104 error = EOPNOTSUPP; 105 break; 106 } 107 108 return (error); 109} 110 111static int 112vtrnd_probe(device_t dev) 113{ 114 115 if (virtio_get_device_type(dev) != VIRTIO_ID_ENTROPY) 116 return (ENXIO); 117 118 device_set_desc(dev, "VirtIO Entropy Adapter"); 119 120 return (BUS_PROBE_DEFAULT); 121} 122 123static int 124vtrnd_attach(device_t dev) 125{ 126 struct vtrnd_softc *sc; 127 int error; 128 129 sc = device_get_softc(dev); 130 sc->vtrnd_dev = dev; 131 132 callout_init(&sc->vtrnd_callout, CALLOUT_MPSAFE); 133 134 virtio_set_feature_desc(dev, vtrnd_feature_desc); 135 vtrnd_negotiate_features(sc); 136 137 error = vtrnd_alloc_virtqueue(sc); 138 if (error) { 139 device_printf(dev, "cannot allocate virtqueue\n"); 140 goto fail; 141 } 142 143 callout_reset(&sc->vtrnd_callout, 5 * hz, vtrnd_timer, sc); 144 145fail: 146 if (error) 147 vtrnd_detach(dev); 148 149 return (error); 150} 151 152static int 153vtrnd_detach(device_t dev) 154{ 155 struct vtrnd_softc *sc; 156 157 sc = device_get_softc(dev); 158
|
159 callout_stop(&sc->vtrnd_callout);
| 159 callout_drain(&sc->vtrnd_callout);
|
160 161 return (0); 162} 163 164static void 165vtrnd_negotiate_features(struct vtrnd_softc *sc) 166{ 167 device_t dev; 168 uint64_t features; 169 170 dev = sc->vtrnd_dev; 171 features = VTRND_FEATURES; 172 173 sc->vtrnd_features = virtio_negotiate_features(dev, features); 174} 175 176static int 177vtrnd_alloc_virtqueue(struct vtrnd_softc *sc) 178{ 179 device_t dev; 180 struct vq_alloc_info vq_info; 181 182 dev = sc->vtrnd_dev; 183 184 VQ_ALLOC_INFO_INIT(&vq_info, 0, NULL, sc, &sc->vtrnd_vq, 185 "%s request", device_get_nameunit(dev)); 186 187 return (virtio_alloc_virtqueues(dev, 0, 1, &vq_info)); 188} 189 190static void 191vtrnd_harvest(struct vtrnd_softc *sc) 192{ 193 struct sglist_seg segs[1]; 194 struct sglist sg; 195 struct virtqueue *vq; 196 uint32_t value; 197 int error; 198 199 vq = sc->vtrnd_vq; 200 201 sglist_init(&sg, 1, segs); 202 error = sglist_append(&sg, &value, sizeof(value)); 203 KASSERT(error == 0 && sg.sg_nseg == 1, 204 ("%s: error %d adding buffer to sglist", __func__, error)); 205 206 if (!virtqueue_empty(vq)) 207 return; 208 if (virtqueue_enqueue(vq, &value, &sg, 0, 1) != 0) 209 return; 210 211 /* 212 * Poll for the response, but the command is likely already 213 * done when we return from the notify. 214 */ 215 virtqueue_notify(vq); 216 virtqueue_poll(vq, NULL); 217 218 random_harvest(&value, sizeof(value), sizeof(value) * NBBY / 2, 219 RANDOM_PURE_VIRTIO); 220} 221 222static void 223vtrnd_timer(void *xsc) 224{ 225 struct vtrnd_softc *sc; 226 227 sc = xsc; 228 229 vtrnd_harvest(sc); 230 callout_schedule(&sc->vtrnd_callout, 5 * hz); 231}
| 160 161 return (0); 162} 163 164static void 165vtrnd_negotiate_features(struct vtrnd_softc *sc) 166{ 167 device_t dev; 168 uint64_t features; 169 170 dev = sc->vtrnd_dev; 171 features = VTRND_FEATURES; 172 173 sc->vtrnd_features = virtio_negotiate_features(dev, features); 174} 175 176static int 177vtrnd_alloc_virtqueue(struct vtrnd_softc *sc) 178{ 179 device_t dev; 180 struct vq_alloc_info vq_info; 181 182 dev = sc->vtrnd_dev; 183 184 VQ_ALLOC_INFO_INIT(&vq_info, 0, NULL, sc, &sc->vtrnd_vq, 185 "%s request", device_get_nameunit(dev)); 186 187 return (virtio_alloc_virtqueues(dev, 0, 1, &vq_info)); 188} 189 190static void 191vtrnd_harvest(struct vtrnd_softc *sc) 192{ 193 struct sglist_seg segs[1]; 194 struct sglist sg; 195 struct virtqueue *vq; 196 uint32_t value; 197 int error; 198 199 vq = sc->vtrnd_vq; 200 201 sglist_init(&sg, 1, segs); 202 error = sglist_append(&sg, &value, sizeof(value)); 203 KASSERT(error == 0 && sg.sg_nseg == 1, 204 ("%s: error %d adding buffer to sglist", __func__, error)); 205 206 if (!virtqueue_empty(vq)) 207 return; 208 if (virtqueue_enqueue(vq, &value, &sg, 0, 1) != 0) 209 return; 210 211 /* 212 * Poll for the response, but the command is likely already 213 * done when we return from the notify. 214 */ 215 virtqueue_notify(vq); 216 virtqueue_poll(vq, NULL); 217 218 random_harvest(&value, sizeof(value), sizeof(value) * NBBY / 2, 219 RANDOM_PURE_VIRTIO); 220} 221 222static void 223vtrnd_timer(void *xsc) 224{ 225 struct vtrnd_softc *sc; 226 227 sc = xsc; 228 229 vtrnd_harvest(sc); 230 callout_schedule(&sc->vtrnd_callout, 5 * hz); 231}
|