virtio.c revision 241394
1227652Sgrehan/*- 2227652Sgrehan * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org> 3227652Sgrehan * All rights reserved. 4227652Sgrehan * 5227652Sgrehan * Redistribution and use in source and binary forms, with or without 6227652Sgrehan * modification, are permitted provided that the following conditions 7227652Sgrehan * are met: 8227652Sgrehan * 1. Redistributions of source code must retain the above copyright 9227652Sgrehan * notice unmodified, this list of conditions, and the following 10227652Sgrehan * disclaimer. 11227652Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 12227652Sgrehan * notice, this list of conditions and the following disclaimer in the 13227652Sgrehan * documentation and/or other materials provided with the distribution. 14227652Sgrehan * 15227652Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16227652Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17227652Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18227652Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19227652Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20227652Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21227652Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22227652Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23227652Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24227652Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25227652Sgrehan */ 26227652Sgrehan 27227652Sgrehan#include <sys/cdefs.h> 28227652Sgrehan__FBSDID("$FreeBSD: head/sys/dev/virtio/virtio.c 241394 2012-10-10 08:36:38Z kevlo $"); 29227652Sgrehan 30227652Sgrehan#include <sys/param.h> 31227652Sgrehan#include <sys/systm.h> 32227652Sgrehan#include <sys/kernel.h> 33227652Sgrehan#include <sys/malloc.h> 34227652Sgrehan#include <sys/module.h> 35227652Sgrehan#include <sys/sbuf.h> 36227652Sgrehan 37227652Sgrehan#include <machine/bus.h> 38227652Sgrehan#include <machine/resource.h> 39227652Sgrehan#include <machine/_inttypes.h> 40227652Sgrehan#include <sys/bus.h> 41227652Sgrehan#include <sys/rman.h> 42227652Sgrehan 43227652Sgrehan#include <dev/virtio/virtio.h> 44227652Sgrehan#include <dev/virtio/virtqueue.h> 45227652Sgrehan 46227652Sgrehan#include "virtio_bus_if.h" 47227652Sgrehan 48227652Sgrehanstatic int virtio_modevent(module_t, int, void *); 49227652Sgrehanstatic const char *virtio_feature_name(uint64_t, struct virtio_feature_desc *); 50227652Sgrehan 51227652Sgrehanstatic struct virtio_ident { 52227652Sgrehan uint16_t devid; 53227652Sgrehan char *name; 54227652Sgrehan} virtio_ident_table[] = { 55227652Sgrehan { VIRTIO_ID_NETWORK, "Network" }, 56227652Sgrehan { VIRTIO_ID_BLOCK, "Block" }, 57227652Sgrehan { VIRTIO_ID_CONSOLE, "Console" }, 58227652Sgrehan { VIRTIO_ID_ENTROPY, "Entropy" }, 59227652Sgrehan { VIRTIO_ID_BALLOON, "Balloon" }, 60227652Sgrehan { VIRTIO_ID_IOMEMORY, "IOMemory" }, 61227652Sgrehan { VIRTIO_ID_9P, "9P Transport" }, 62227652Sgrehan 63227652Sgrehan { 0, NULL } 64227652Sgrehan}; 65227652Sgrehan 66227652Sgrehan/* Device independent features. */ 67227652Sgrehanstatic struct virtio_feature_desc virtio_common_feature_desc[] = { 68227652Sgrehan { VIRTIO_F_NOTIFY_ON_EMPTY, "NotifyOnEmpty" }, 69227652Sgrehan { VIRTIO_RING_F_INDIRECT_DESC, "RingIndirect" }, 70227652Sgrehan { VIRTIO_RING_F_EVENT_IDX, "EventIdx" }, 71227652Sgrehan { VIRTIO_F_BAD_FEATURE, "BadFeature" }, 72227652Sgrehan 73227652Sgrehan { 0, NULL } 74227652Sgrehan}; 75227652Sgrehan 76227652Sgrehanconst char * 77227652Sgrehanvirtio_device_name(uint16_t devid) 78227652Sgrehan{ 79227652Sgrehan struct virtio_ident *ident; 80227652Sgrehan 81227652Sgrehan for (ident = virtio_ident_table; ident->name != NULL; ident++) { 82227652Sgrehan if (ident->devid == devid) 83227652Sgrehan return (ident->name); 84227652Sgrehan } 85227652Sgrehan 86227652Sgrehan return (NULL); 87227652Sgrehan} 88227652Sgrehan 89227652Sgrehanvoid 90227652Sgrehanvirtio_describe(device_t dev, const char *msg, 91227652Sgrehan uint64_t features, struct virtio_feature_desc *feature_desc) 92227652Sgrehan{ 93227652Sgrehan struct sbuf sb; 94227652Sgrehan uint64_t val; 95227652Sgrehan char *buf; 96227652Sgrehan const char *name; 97227652Sgrehan int n; 98227652Sgrehan 99227652Sgrehan if ((buf = malloc(512, M_TEMP, M_NOWAIT)) == NULL) { 100227652Sgrehan device_printf(dev, "%s features: 0x%"PRIx64"\n", msg, 101227652Sgrehan features); 102227652Sgrehan return; 103227652Sgrehan } 104227652Sgrehan 105227652Sgrehan sbuf_new(&sb, buf, 512, SBUF_FIXEDLEN); 106227652Sgrehan sbuf_printf(&sb, "%s features: 0x%"PRIx64, msg, features); 107227652Sgrehan 108227652Sgrehan for (n = 0, val = 1ULL << 63; val != 0; val >>= 1) { 109227652Sgrehan /* 110227652Sgrehan * BAD_FEATURE is used to detect broken Linux clients 111227652Sgrehan * and therefore is not applicable to FreeBSD. 112227652Sgrehan */ 113227652Sgrehan if (((features & val) == 0) || val == VIRTIO_F_BAD_FEATURE) 114227652Sgrehan continue; 115227652Sgrehan 116227652Sgrehan if (n++ == 0) 117227652Sgrehan sbuf_cat(&sb, " <"); 118227652Sgrehan else 119227652Sgrehan sbuf_cat(&sb, ","); 120227652Sgrehan 121227652Sgrehan name = NULL; 122227652Sgrehan if (feature_desc != NULL) 123227652Sgrehan name = virtio_feature_name(val, feature_desc); 124227652Sgrehan if (name == NULL) 125227652Sgrehan name = virtio_feature_name(val, 126227652Sgrehan virtio_common_feature_desc); 127227652Sgrehan 128227652Sgrehan if (name == NULL) 129227652Sgrehan sbuf_printf(&sb, "0x%"PRIx64, val); 130227652Sgrehan else 131227652Sgrehan sbuf_cat(&sb, name); 132227652Sgrehan } 133227652Sgrehan 134227652Sgrehan if (n > 0) 135227652Sgrehan sbuf_cat(&sb, ">"); 136227652Sgrehan 137227652Sgrehan#if __FreeBSD_version < 900020 138227652Sgrehan sbuf_finish(&sb); 139227652Sgrehan if (sbuf_overflowed(&sb) == 0) 140227652Sgrehan#else 141227652Sgrehan if (sbuf_finish(&sb) == 0) 142227652Sgrehan#endif 143227652Sgrehan device_printf(dev, "%s\n", sbuf_data(&sb)); 144227652Sgrehan 145227652Sgrehan sbuf_delete(&sb); 146227652Sgrehan free(buf, M_TEMP); 147227652Sgrehan} 148227652Sgrehan 149227652Sgrehanstatic const char * 150227652Sgrehanvirtio_feature_name(uint64_t val, struct virtio_feature_desc *feature_desc) 151227652Sgrehan{ 152227652Sgrehan int i; 153227652Sgrehan 154227652Sgrehan for (i = 0; feature_desc[i].vfd_val != 0; i++) 155227652Sgrehan if (val == feature_desc[i].vfd_val) 156227652Sgrehan return (feature_desc[i].vfd_str); 157227652Sgrehan 158227652Sgrehan return (NULL); 159227652Sgrehan} 160227652Sgrehan 161227652Sgrehan/* 162227652Sgrehan * VirtIO bus method wrappers. 163227652Sgrehan */ 164227652Sgrehan 165238360Sgrehanvoid 166238360Sgrehanvirtio_read_ivar(device_t dev, int ivar, uintptr_t *val) 167238360Sgrehan{ 168238360Sgrehan 169238360Sgrehan *val = -1; 170238360Sgrehan BUS_READ_IVAR(device_get_parent(dev), dev, ivar, val); 171238360Sgrehan} 172238360Sgrehan 173238360Sgrehanvoid 174238360Sgrehanvirtio_write_ivar(device_t dev, int ivar, uintptr_t val) 175238360Sgrehan{ 176238360Sgrehan 177238360Sgrehan BUS_WRITE_IVAR(device_get_parent(dev), dev, ivar, val); 178238360Sgrehan} 179238360Sgrehan 180227652Sgrehanuint64_t 181227652Sgrehanvirtio_negotiate_features(device_t dev, uint64_t child_features) 182227652Sgrehan{ 183227652Sgrehan 184227652Sgrehan return (VIRTIO_BUS_NEGOTIATE_FEATURES(device_get_parent(dev), 185227652Sgrehan child_features)); 186227652Sgrehan} 187227652Sgrehan 188227652Sgrehanint 189227652Sgrehanvirtio_alloc_virtqueues(device_t dev, int flags, int nvqs, 190227652Sgrehan struct vq_alloc_info *info) 191227652Sgrehan{ 192227652Sgrehan 193227652Sgrehan return (VIRTIO_BUS_ALLOC_VIRTQUEUES(device_get_parent(dev), flags, 194227652Sgrehan nvqs, info)); 195227652Sgrehan} 196227652Sgrehan 197227652Sgrehanint 198227652Sgrehanvirtio_setup_intr(device_t dev, enum intr_type type) 199227652Sgrehan{ 200227652Sgrehan 201227652Sgrehan return (VIRTIO_BUS_SETUP_INTR(device_get_parent(dev), type)); 202227652Sgrehan} 203227652Sgrehan 204227652Sgrehanint 205227652Sgrehanvirtio_with_feature(device_t dev, uint64_t feature) 206227652Sgrehan{ 207227652Sgrehan 208227652Sgrehan return (VIRTIO_BUS_WITH_FEATURE(device_get_parent(dev), feature)); 209227652Sgrehan} 210227652Sgrehan 211227652Sgrehanvoid 212227652Sgrehanvirtio_stop(device_t dev) 213227652Sgrehan{ 214227652Sgrehan 215227652Sgrehan VIRTIO_BUS_STOP(device_get_parent(dev)); 216227652Sgrehan} 217227652Sgrehan 218227652Sgrehanint 219227652Sgrehanvirtio_reinit(device_t dev, uint64_t features) 220227652Sgrehan{ 221227652Sgrehan 222227652Sgrehan return (VIRTIO_BUS_REINIT(device_get_parent(dev), features)); 223227652Sgrehan} 224227652Sgrehan 225227652Sgrehanvoid 226227652Sgrehanvirtio_reinit_complete(device_t dev) 227227652Sgrehan{ 228227652Sgrehan 229227652Sgrehan VIRTIO_BUS_REINIT_COMPLETE(device_get_parent(dev)); 230227652Sgrehan} 231227652Sgrehan 232227652Sgrehanvoid 233227652Sgrehanvirtio_read_device_config(device_t dev, bus_size_t offset, void *dst, int len) 234227652Sgrehan{ 235227652Sgrehan 236227652Sgrehan VIRTIO_BUS_READ_DEVICE_CONFIG(device_get_parent(dev), 237227652Sgrehan offset, dst, len); 238227652Sgrehan} 239227652Sgrehan 240227652Sgrehanvoid 241227652Sgrehanvirtio_write_device_config(device_t dev, bus_size_t offset, void *dst, int len) 242227652Sgrehan{ 243227652Sgrehan 244227652Sgrehan VIRTIO_BUS_WRITE_DEVICE_CONFIG(device_get_parent(dev), 245227652Sgrehan offset, dst, len); 246227652Sgrehan} 247227652Sgrehan 248227652Sgrehanstatic int 249227652Sgrehanvirtio_modevent(module_t mod, int type, void *unused) 250227652Sgrehan{ 251227652Sgrehan int error; 252227652Sgrehan 253227652Sgrehan error = 0; 254227652Sgrehan 255227652Sgrehan switch (type) { 256227652Sgrehan case MOD_LOAD: 257227652Sgrehan case MOD_QUIESCE: 258227652Sgrehan case MOD_UNLOAD: 259227652Sgrehan case MOD_SHUTDOWN: 260227652Sgrehan break; 261227652Sgrehan default: 262227652Sgrehan error = EOPNOTSUPP; 263227652Sgrehan break; 264227652Sgrehan } 265227652Sgrehan 266227652Sgrehan return (error); 267227652Sgrehan} 268227652Sgrehan 269227652Sgrehanstatic moduledata_t virtio_mod = { 270227652Sgrehan "virtio", 271227652Sgrehan virtio_modevent, 272241394Skevlo 0 273227652Sgrehan}; 274227652Sgrehan 275227652SgrehanDECLARE_MODULE(virtio, virtio_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 276227652SgrehanMODULE_VERSION(virtio, 1); 277