virtio.c revision 227652
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 227652 2011-11-18 05:43:43Z grehan $"); 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 89227652Sgrehanint 90227652Sgrehanvirtio_get_device_type(device_t dev) 91227652Sgrehan{ 92227652Sgrehan uintptr_t devtype; 93227652Sgrehan 94227652Sgrehan devtype = -1; 95227652Sgrehan 96227652Sgrehan BUS_READ_IVAR(device_get_parent(dev), dev, 97227652Sgrehan VIRTIO_IVAR_DEVTYPE, &devtype); 98227652Sgrehan 99227652Sgrehan return ((int) devtype); 100227652Sgrehan} 101227652Sgrehan 102227652Sgrehanvoid 103227652Sgrehanvirtio_set_feature_desc(device_t dev, 104227652Sgrehan struct virtio_feature_desc *feature_desc) 105227652Sgrehan{ 106227652Sgrehan 107227652Sgrehan BUS_WRITE_IVAR(device_get_parent(dev), dev, 108227652Sgrehan VIRTIO_IVAR_FEATURE_DESC, (uintptr_t) feature_desc); 109227652Sgrehan} 110227652Sgrehan 111227652Sgrehanvoid 112227652Sgrehanvirtio_describe(device_t dev, const char *msg, 113227652Sgrehan uint64_t features, struct virtio_feature_desc *feature_desc) 114227652Sgrehan{ 115227652Sgrehan struct sbuf sb; 116227652Sgrehan uint64_t val; 117227652Sgrehan char *buf; 118227652Sgrehan const char *name; 119227652Sgrehan int n; 120227652Sgrehan 121227652Sgrehan if ((buf = malloc(512, M_TEMP, M_NOWAIT)) == NULL) { 122227652Sgrehan device_printf(dev, "%s features: 0x%"PRIx64"\n", msg, 123227652Sgrehan features); 124227652Sgrehan return; 125227652Sgrehan } 126227652Sgrehan 127227652Sgrehan sbuf_new(&sb, buf, 512, SBUF_FIXEDLEN); 128227652Sgrehan sbuf_printf(&sb, "%s features: 0x%"PRIx64, msg, features); 129227652Sgrehan 130227652Sgrehan for (n = 0, val = 1ULL << 63; val != 0; val >>= 1) { 131227652Sgrehan /* 132227652Sgrehan * BAD_FEATURE is used to detect broken Linux clients 133227652Sgrehan * and therefore is not applicable to FreeBSD. 134227652Sgrehan */ 135227652Sgrehan if (((features & val) == 0) || val == VIRTIO_F_BAD_FEATURE) 136227652Sgrehan continue; 137227652Sgrehan 138227652Sgrehan if (n++ == 0) 139227652Sgrehan sbuf_cat(&sb, " <"); 140227652Sgrehan else 141227652Sgrehan sbuf_cat(&sb, ","); 142227652Sgrehan 143227652Sgrehan name = NULL; 144227652Sgrehan if (feature_desc != NULL) 145227652Sgrehan name = virtio_feature_name(val, feature_desc); 146227652Sgrehan if (name == NULL) 147227652Sgrehan name = virtio_feature_name(val, 148227652Sgrehan virtio_common_feature_desc); 149227652Sgrehan 150227652Sgrehan if (name == NULL) 151227652Sgrehan sbuf_printf(&sb, "0x%"PRIx64, val); 152227652Sgrehan else 153227652Sgrehan sbuf_cat(&sb, name); 154227652Sgrehan } 155227652Sgrehan 156227652Sgrehan if (n > 0) 157227652Sgrehan sbuf_cat(&sb, ">"); 158227652Sgrehan 159227652Sgrehan#if __FreeBSD_version < 900020 160227652Sgrehan sbuf_finish(&sb); 161227652Sgrehan if (sbuf_overflowed(&sb) == 0) 162227652Sgrehan#else 163227652Sgrehan if (sbuf_finish(&sb) == 0) 164227652Sgrehan#endif 165227652Sgrehan device_printf(dev, "%s\n", sbuf_data(&sb)); 166227652Sgrehan 167227652Sgrehan sbuf_delete(&sb); 168227652Sgrehan free(buf, M_TEMP); 169227652Sgrehan} 170227652Sgrehan 171227652Sgrehanstatic const char * 172227652Sgrehanvirtio_feature_name(uint64_t val, struct virtio_feature_desc *feature_desc) 173227652Sgrehan{ 174227652Sgrehan int i; 175227652Sgrehan 176227652Sgrehan for (i = 0; feature_desc[i].vfd_val != 0; i++) 177227652Sgrehan if (val == feature_desc[i].vfd_val) 178227652Sgrehan return (feature_desc[i].vfd_str); 179227652Sgrehan 180227652Sgrehan return (NULL); 181227652Sgrehan} 182227652Sgrehan 183227652Sgrehan/* 184227652Sgrehan * VirtIO bus method wrappers. 185227652Sgrehan */ 186227652Sgrehan 187227652Sgrehanuint64_t 188227652Sgrehanvirtio_negotiate_features(device_t dev, uint64_t child_features) 189227652Sgrehan{ 190227652Sgrehan 191227652Sgrehan return (VIRTIO_BUS_NEGOTIATE_FEATURES(device_get_parent(dev), 192227652Sgrehan child_features)); 193227652Sgrehan} 194227652Sgrehan 195227652Sgrehanint 196227652Sgrehanvirtio_alloc_virtqueues(device_t dev, int flags, int nvqs, 197227652Sgrehan struct vq_alloc_info *info) 198227652Sgrehan{ 199227652Sgrehan 200227652Sgrehan return (VIRTIO_BUS_ALLOC_VIRTQUEUES(device_get_parent(dev), flags, 201227652Sgrehan nvqs, info)); 202227652Sgrehan} 203227652Sgrehan 204227652Sgrehanint 205227652Sgrehanvirtio_setup_intr(device_t dev, enum intr_type type) 206227652Sgrehan{ 207227652Sgrehan 208227652Sgrehan return (VIRTIO_BUS_SETUP_INTR(device_get_parent(dev), type)); 209227652Sgrehan} 210227652Sgrehan 211227652Sgrehanint 212227652Sgrehanvirtio_with_feature(device_t dev, uint64_t feature) 213227652Sgrehan{ 214227652Sgrehan 215227652Sgrehan return (VIRTIO_BUS_WITH_FEATURE(device_get_parent(dev), feature)); 216227652Sgrehan} 217227652Sgrehan 218227652Sgrehanvoid 219227652Sgrehanvirtio_stop(device_t dev) 220227652Sgrehan{ 221227652Sgrehan 222227652Sgrehan VIRTIO_BUS_STOP(device_get_parent(dev)); 223227652Sgrehan} 224227652Sgrehan 225227652Sgrehanint 226227652Sgrehanvirtio_reinit(device_t dev, uint64_t features) 227227652Sgrehan{ 228227652Sgrehan 229227652Sgrehan return (VIRTIO_BUS_REINIT(device_get_parent(dev), features)); 230227652Sgrehan} 231227652Sgrehan 232227652Sgrehanvoid 233227652Sgrehanvirtio_reinit_complete(device_t dev) 234227652Sgrehan{ 235227652Sgrehan 236227652Sgrehan VIRTIO_BUS_REINIT_COMPLETE(device_get_parent(dev)); 237227652Sgrehan} 238227652Sgrehan 239227652Sgrehanvoid 240227652Sgrehanvirtio_read_device_config(device_t dev, bus_size_t offset, void *dst, int len) 241227652Sgrehan{ 242227652Sgrehan 243227652Sgrehan VIRTIO_BUS_READ_DEVICE_CONFIG(device_get_parent(dev), 244227652Sgrehan offset, dst, len); 245227652Sgrehan} 246227652Sgrehan 247227652Sgrehanvoid 248227652Sgrehanvirtio_write_device_config(device_t dev, bus_size_t offset, void *dst, int len) 249227652Sgrehan{ 250227652Sgrehan 251227652Sgrehan VIRTIO_BUS_WRITE_DEVICE_CONFIG(device_get_parent(dev), 252227652Sgrehan offset, dst, len); 253227652Sgrehan} 254227652Sgrehan 255227652Sgrehanstatic int 256227652Sgrehanvirtio_modevent(module_t mod, int type, void *unused) 257227652Sgrehan{ 258227652Sgrehan int error; 259227652Sgrehan 260227652Sgrehan error = 0; 261227652Sgrehan 262227652Sgrehan switch (type) { 263227652Sgrehan case MOD_LOAD: 264227652Sgrehan case MOD_QUIESCE: 265227652Sgrehan case MOD_UNLOAD: 266227652Sgrehan case MOD_SHUTDOWN: 267227652Sgrehan break; 268227652Sgrehan default: 269227652Sgrehan error = EOPNOTSUPP; 270227652Sgrehan break; 271227652Sgrehan } 272227652Sgrehan 273227652Sgrehan return (error); 274227652Sgrehan} 275227652Sgrehan 276227652Sgrehanstatic moduledata_t virtio_mod = { 277227652Sgrehan "virtio", 278227652Sgrehan virtio_modevent, 279227652Sgrehan 0 280227652Sgrehan}; 281227652Sgrehan 282227652SgrehanDECLARE_MODULE(virtio, virtio_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 283227652SgrehanMODULE_VERSION(virtio, 1); 284