xref: /dragonfly/sys/dev/virtual/virtio/virtio/virtio.c (revision 8afeec5d)
111447b59SVenkatesh Srinivas /*-
211447b59SVenkatesh Srinivas  * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org>
311447b59SVenkatesh Srinivas  * All rights reserved.
411447b59SVenkatesh Srinivas  *
511447b59SVenkatesh Srinivas  * Redistribution and use in source and binary forms, with or without
611447b59SVenkatesh Srinivas  * modification, are permitted provided that the following conditions
711447b59SVenkatesh Srinivas  * are met:
811447b59SVenkatesh Srinivas  * 1. Redistributions of source code must retain the above copyright
911447b59SVenkatesh Srinivas  *    notice unmodified, this list of conditions, and the following
1011447b59SVenkatesh Srinivas  *    disclaimer.
1111447b59SVenkatesh Srinivas  * 2. Redistributions in binary form must reproduce the above copyright
1211447b59SVenkatesh Srinivas  *    notice, this list of conditions and the following disclaimer in the
1311447b59SVenkatesh Srinivas  *    documentation and/or other materials provided with the distribution.
1411447b59SVenkatesh Srinivas  *
1511447b59SVenkatesh Srinivas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1611447b59SVenkatesh Srinivas  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1711447b59SVenkatesh Srinivas  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1811447b59SVenkatesh Srinivas  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1911447b59SVenkatesh Srinivas  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2011447b59SVenkatesh Srinivas  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2111447b59SVenkatesh Srinivas  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2211447b59SVenkatesh Srinivas  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2311447b59SVenkatesh Srinivas  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2411447b59SVenkatesh Srinivas  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2511447b59SVenkatesh Srinivas  *
2611447b59SVenkatesh Srinivas  * $FreeBSD: src/sys/dev/virtio/virtio.c,v 1.1 2011/11/18 05:43:43 grehan Exp $
2711447b59SVenkatesh Srinivas  */
2811447b59SVenkatesh Srinivas 
2911447b59SVenkatesh Srinivas #include <sys/param.h>
3011447b59SVenkatesh Srinivas #include <sys/systm.h>
3111447b59SVenkatesh Srinivas #include <sys/kernel.h>
3211447b59SVenkatesh Srinivas #include <sys/malloc.h>
3311447b59SVenkatesh Srinivas #include <sys/module.h>
3411447b59SVenkatesh Srinivas #include <sys/sbuf.h>
3511447b59SVenkatesh Srinivas 
3611447b59SVenkatesh Srinivas #include <machine/inttypes.h>
3711447b59SVenkatesh Srinivas #include <sys/bus.h>
382f1382caSVenkatesh Srinivas #include <sys/serialize.h>
3911447b59SVenkatesh Srinivas #include <sys/rman.h>
4011447b59SVenkatesh Srinivas 
4111447b59SVenkatesh Srinivas #include "virtio.h"
4211447b59SVenkatesh Srinivas #include "virtqueue.h"
4311447b59SVenkatesh Srinivas 
4411447b59SVenkatesh Srinivas #include "virtio_bus_if.h"
4511447b59SVenkatesh Srinivas 
4611447b59SVenkatesh Srinivas static int virtio_modevent(module_t, int, void *);
4711447b59SVenkatesh Srinivas static const char *virtio_feature_name(uint64_t, struct virtio_feature_desc *);
4811447b59SVenkatesh Srinivas 
4911447b59SVenkatesh Srinivas static struct virtio_ident {
5011447b59SVenkatesh Srinivas 	uint16_t devid;
51866fc571SSascha Wildner 	const char *name;
5211447b59SVenkatesh Srinivas } virtio_ident_table[] = {
5311447b59SVenkatesh Srinivas 	{ VIRTIO_ID_NETWORK,	"Network"	},
5411447b59SVenkatesh Srinivas 	{ VIRTIO_ID_BLOCK,	"Block"		},
5511447b59SVenkatesh Srinivas 	{ VIRTIO_ID_CONSOLE,	"Console"	},
5611447b59SVenkatesh Srinivas 	{ VIRTIO_ID_ENTROPY,	"Entropy"	},
5711447b59SVenkatesh Srinivas 	{ VIRTIO_ID_BALLOON,	"Balloon"	},
5811447b59SVenkatesh Srinivas 	{ VIRTIO_ID_IOMEMORY,	"IOMemory"	},
59eff15082SSascha Wildner 	{ VIRTIO_ID_SCSI,	"SCSI"		},
6011447b59SVenkatesh Srinivas 	{ VIRTIO_ID_9P,		"9P Transport"	},
6111447b59SVenkatesh Srinivas 
6211447b59SVenkatesh Srinivas 	{ 0, NULL }
6311447b59SVenkatesh Srinivas };
6411447b59SVenkatesh Srinivas 
6511447b59SVenkatesh Srinivas /* Device independent features. */
6611447b59SVenkatesh Srinivas static struct virtio_feature_desc virtio_common_feature_desc[] = {
6711447b59SVenkatesh Srinivas 	{ VIRTIO_F_NOTIFY_ON_EMPTY,	"NotifyOnEmpty"	},
680ef60afdSImre Vadász 	{ VIRTIO_F_ANY_LAYOUT, 		"AnyLayout"	},
699e39c380SImre Vadász 	{ VIRTIO_RING_F_INDIRECT_DESC,	"RingIndirect"	},
7011447b59SVenkatesh Srinivas 	{ VIRTIO_RING_F_EVENT_IDX,	"EventIdx"	},
7111447b59SVenkatesh Srinivas 	{ VIRTIO_F_BAD_FEATURE,		"BadFeature"	},
7211447b59SVenkatesh Srinivas 
7311447b59SVenkatesh Srinivas 	{ 0, NULL }
7411447b59SVenkatesh Srinivas };
7511447b59SVenkatesh Srinivas 
7611447b59SVenkatesh Srinivas const char *
virtio_device_name(uint16_t devid)7711447b59SVenkatesh Srinivas virtio_device_name(uint16_t devid)
7811447b59SVenkatesh Srinivas {
7911447b59SVenkatesh Srinivas 	struct virtio_ident *ident;
8011447b59SVenkatesh Srinivas 
8111447b59SVenkatesh Srinivas 	for (ident = virtio_ident_table; ident->name != NULL; ident++) {
8211447b59SVenkatesh Srinivas 		if (ident->devid == devid)
8311447b59SVenkatesh Srinivas 			return (ident->name);
8411447b59SVenkatesh Srinivas 	}
8511447b59SVenkatesh Srinivas 
8611447b59SVenkatesh Srinivas 	return (NULL);
8711447b59SVenkatesh Srinivas }
8811447b59SVenkatesh Srinivas 
8911447b59SVenkatesh Srinivas int
virtio_get_device_type(device_t dev)9011447b59SVenkatesh Srinivas virtio_get_device_type(device_t dev)
9111447b59SVenkatesh Srinivas {
9211447b59SVenkatesh Srinivas 	uintptr_t devtype;
9311447b59SVenkatesh Srinivas 
9411447b59SVenkatesh Srinivas 	devtype = -1;
9511447b59SVenkatesh Srinivas 
9611447b59SVenkatesh Srinivas 	BUS_READ_IVAR(device_get_parent(dev), dev,
9711447b59SVenkatesh Srinivas 	    VIRTIO_IVAR_DEVTYPE, &devtype);
9811447b59SVenkatesh Srinivas 
9911447b59SVenkatesh Srinivas 	return ((int) devtype);
10011447b59SVenkatesh Srinivas }
10111447b59SVenkatesh Srinivas 
10211447b59SVenkatesh Srinivas void
virtio_set_feature_desc(device_t dev,struct virtio_feature_desc * feature_desc)10311447b59SVenkatesh Srinivas virtio_set_feature_desc(device_t dev,
10411447b59SVenkatesh Srinivas     struct virtio_feature_desc *feature_desc)
10511447b59SVenkatesh Srinivas {
10611447b59SVenkatesh Srinivas 
10711447b59SVenkatesh Srinivas 	BUS_WRITE_IVAR(device_get_parent(dev), dev,
10811447b59SVenkatesh Srinivas 	    VIRTIO_IVAR_FEATURE_DESC, (uintptr_t) feature_desc);
10911447b59SVenkatesh Srinivas }
11011447b59SVenkatesh Srinivas 
11111447b59SVenkatesh Srinivas void
virtio_describe(device_t dev,const char * msg,uint64_t features,struct virtio_feature_desc * desc)11211447b59SVenkatesh Srinivas virtio_describe(device_t dev, const char *msg,
113a77a4c8cSFrançois Tigeot     uint64_t features, struct virtio_feature_desc *desc)
11411447b59SVenkatesh Srinivas {
11511447b59SVenkatesh Srinivas 	struct sbuf sb;
11611447b59SVenkatesh Srinivas 	uint64_t val;
11711447b59SVenkatesh Srinivas 	char *buf;
11811447b59SVenkatesh Srinivas 	const char *name;
11911447b59SVenkatesh Srinivas 	int n;
12011447b59SVenkatesh Srinivas 
121eb55c32fSMatthew Dillon 	if ((buf = kmalloc(512, M_TEMP, M_INTWAIT)) == NULL) {
12211447b59SVenkatesh Srinivas 		device_printf(dev, "%s features: 0x%"PRIx64"\n", msg,
12311447b59SVenkatesh Srinivas 		    features);
12411447b59SVenkatesh Srinivas 		return;
12511447b59SVenkatesh Srinivas 	}
12611447b59SVenkatesh Srinivas 
12711447b59SVenkatesh Srinivas 	sbuf_new(&sb, buf, 512, SBUF_FIXEDLEN);
12811447b59SVenkatesh Srinivas 	sbuf_printf(&sb, "%s features: 0x%"PRIx64, msg, features);
12911447b59SVenkatesh Srinivas 
13011447b59SVenkatesh Srinivas 	for (n = 0, val = 1ULL << 63; val != 0; val >>= 1) {
13111447b59SVenkatesh Srinivas 		/*
13211447b59SVenkatesh Srinivas 		 * BAD_FEATURE is used to detect broken Linux clients
13311447b59SVenkatesh Srinivas 		 * and therefore is not applicable to FreeBSD.
13411447b59SVenkatesh Srinivas 		 */
13511447b59SVenkatesh Srinivas 		if (((features & val) == 0) || val == VIRTIO_F_BAD_FEATURE)
13611447b59SVenkatesh Srinivas 			continue;
13711447b59SVenkatesh Srinivas 
13811447b59SVenkatesh Srinivas 		if (n++ == 0)
13911447b59SVenkatesh Srinivas 			sbuf_cat(&sb, " <");
14011447b59SVenkatesh Srinivas 		else
14111447b59SVenkatesh Srinivas 			sbuf_cat(&sb, ",");
14211447b59SVenkatesh Srinivas 
143a77a4c8cSFrançois Tigeot 		name = virtio_feature_name(val, desc);
14411447b59SVenkatesh Srinivas 		if (name == NULL)
145a77a4c8cSFrançois Tigeot 			sbuf_printf(&sb, "%#jx", (uintmax_t) val);
14611447b59SVenkatesh Srinivas 		else
14711447b59SVenkatesh Srinivas 			sbuf_cat(&sb, name);
14811447b59SVenkatesh Srinivas 	}
14911447b59SVenkatesh Srinivas 
15011447b59SVenkatesh Srinivas 	if (n > 0)
15111447b59SVenkatesh Srinivas 		sbuf_cat(&sb, ">");
15211447b59SVenkatesh Srinivas 
153a77a4c8cSFrançois Tigeot 	if (sbuf_finish(&sb) == 0)
15411447b59SVenkatesh Srinivas 		device_printf(dev, "%s\n", sbuf_data(&sb));
15511447b59SVenkatesh Srinivas 
15611447b59SVenkatesh Srinivas 	sbuf_delete(&sb);
15711447b59SVenkatesh Srinivas 	kfree(buf, M_TEMP);
15811447b59SVenkatesh Srinivas }
15911447b59SVenkatesh Srinivas 
16011447b59SVenkatesh Srinivas static const char *
virtio_feature_name(uint64_t val,struct virtio_feature_desc * desc)161a77a4c8cSFrançois Tigeot virtio_feature_name(uint64_t val, struct virtio_feature_desc *desc)
16211447b59SVenkatesh Srinivas {
163a77a4c8cSFrançois Tigeot 	int i, j;
164a77a4c8cSFrançois Tigeot 	struct virtio_feature_desc *descs[2] = { desc,
165a77a4c8cSFrançois Tigeot 	    virtio_common_feature_desc };
16611447b59SVenkatesh Srinivas 
167a77a4c8cSFrançois Tigeot 	for (i = 0; i < 2; i++) {
168a77a4c8cSFrançois Tigeot 		if (descs[i] == NULL)
169a77a4c8cSFrançois Tigeot 			continue;
170a77a4c8cSFrançois Tigeot 
171a77a4c8cSFrançois Tigeot 		for (j = 0; descs[i][j].vfd_val != 0; j++) {
172a77a4c8cSFrançois Tigeot 			if (val == descs[i][j].vfd_val)
173a77a4c8cSFrançois Tigeot 				return (descs[i][j].vfd_str);
174a77a4c8cSFrançois Tigeot 		}
175a77a4c8cSFrançois Tigeot 	}
17611447b59SVenkatesh Srinivas 
17711447b59SVenkatesh Srinivas 	return (NULL);
17811447b59SVenkatesh Srinivas }
17911447b59SVenkatesh Srinivas 
18011447b59SVenkatesh Srinivas /*
18111447b59SVenkatesh Srinivas  * VirtIO bus method wrappers.
18211447b59SVenkatesh Srinivas  */
18311447b59SVenkatesh Srinivas 
18411447b59SVenkatesh Srinivas uint64_t
virtio_negotiate_features(device_t dev,uint64_t child_features)18511447b59SVenkatesh Srinivas virtio_negotiate_features(device_t dev, uint64_t child_features)
18611447b59SVenkatesh Srinivas {
18711447b59SVenkatesh Srinivas 	return (VIRTIO_BUS_NEGOTIATE_FEATURES(device_get_parent(dev),
18811447b59SVenkatesh Srinivas 		child_features));
18911447b59SVenkatesh Srinivas }
19011447b59SVenkatesh Srinivas 
19111447b59SVenkatesh Srinivas int
virtio_alloc_virtqueues(device_t dev,int nvqs,struct vq_alloc_info * info)192099c4d8eSImre Vadász virtio_alloc_virtqueues(device_t dev, int nvqs, struct vq_alloc_info *info)
19311447b59SVenkatesh Srinivas {
194099c4d8eSImre Vadász 	return (VIRTIO_BUS_ALLOC_VIRTQUEUES(device_get_parent(dev),
19511447b59SVenkatesh Srinivas 		nvqs, info));
19611447b59SVenkatesh Srinivas }
19711447b59SVenkatesh Srinivas 
19811447b59SVenkatesh Srinivas int
virtio_setup_intr(device_t dev,uint irq,lwkt_serialize_t slz)1992f2405bbSImre Vadász virtio_setup_intr(device_t dev, uint irq, lwkt_serialize_t slz)
20011447b59SVenkatesh Srinivas {
2012f2405bbSImre Vadász 	return (VIRTIO_BUS_SETUP_INTR(device_get_parent(dev), irq, slz));
2022f2405bbSImre Vadász }
2032f2405bbSImre Vadász 
2042f2405bbSImre Vadász int
virtio_teardown_intr(device_t dev,uint irq)2052f2405bbSImre Vadász virtio_teardown_intr(device_t dev, uint irq)
2062f2405bbSImre Vadász {
2072f2405bbSImre Vadász 	return (VIRTIO_BUS_TEARDOWN_INTR(device_get_parent(dev), irq));
2082f2405bbSImre Vadász }
2092f2405bbSImre Vadász 
2102f2405bbSImre Vadász int
virtio_intr_count(device_t dev)2112f2405bbSImre Vadász virtio_intr_count(device_t dev)
2122f2405bbSImre Vadász {
2132f2405bbSImre Vadász 	return (VIRTIO_BUS_INTR_COUNT(device_get_parent(dev)));
2142f2405bbSImre Vadász }
2152f2405bbSImre Vadász 
2162f2405bbSImre Vadász int
virtio_intr_alloc(device_t dev,int * cnt,int use_config,int * cpus)2172f2405bbSImre Vadász virtio_intr_alloc(device_t dev, int *cnt, int use_config, int *cpus)
2182f2405bbSImre Vadász {
2192f2405bbSImre Vadász 	return (VIRTIO_BUS_INTR_ALLOC(device_get_parent(dev), cnt, use_config,
2202f2405bbSImre Vadász 				      cpus));
2212f2405bbSImre Vadász }
2222f2405bbSImre Vadász 
2232f2405bbSImre Vadász int
virtio_intr_release(device_t dev)2242f2405bbSImre Vadász virtio_intr_release(device_t dev)
2252f2405bbSImre Vadász {
2262f2405bbSImre Vadász 	return (VIRTIO_BUS_INTR_RELEASE(device_get_parent(dev)));
2272f2405bbSImre Vadász }
2282f2405bbSImre Vadász 
2292f2405bbSImre Vadász int
virtio_bind_intr(device_t dev,uint irq,int what,driver_intr_t handler,void * arg)2309d96478cSImre Vadász virtio_bind_intr(device_t dev, uint irq, int what,
2319d96478cSImre Vadász     driver_intr_t handler, void *arg)
2322f2405bbSImre Vadász {
2339d96478cSImre Vadász 	return (VIRTIO_BUS_BIND_INTR(device_get_parent(dev), irq, what,
2349d96478cSImre Vadász 				     handler, arg));
2352f2405bbSImre Vadász }
2362f2405bbSImre Vadász 
2372f2405bbSImre Vadász int
virtio_unbind_intr(device_t dev,int what)2382f2405bbSImre Vadász virtio_unbind_intr(device_t dev, int what)
2392f2405bbSImre Vadász {
2402f2405bbSImre Vadász 	return (VIRTIO_BUS_UNBIND_INTR(device_get_parent(dev), what));
24111447b59SVenkatesh Srinivas }
24211447b59SVenkatesh Srinivas 
24311447b59SVenkatesh Srinivas int
virtio_with_feature(device_t dev,uint64_t feature)24411447b59SVenkatesh Srinivas virtio_with_feature(device_t dev, uint64_t feature)
24511447b59SVenkatesh Srinivas {
24611447b59SVenkatesh Srinivas 	return (VIRTIO_BUS_WITH_FEATURE(device_get_parent(dev), feature));
24711447b59SVenkatesh Srinivas }
24811447b59SVenkatesh Srinivas 
24911447b59SVenkatesh Srinivas void
virtio_stop(device_t dev)25011447b59SVenkatesh Srinivas virtio_stop(device_t dev)
25111447b59SVenkatesh Srinivas {
25211447b59SVenkatesh Srinivas 	VIRTIO_BUS_STOP(device_get_parent(dev));
25311447b59SVenkatesh Srinivas }
25411447b59SVenkatesh Srinivas 
25511447b59SVenkatesh Srinivas int
virtio_reinit(device_t dev,uint64_t features)25611447b59SVenkatesh Srinivas virtio_reinit(device_t dev, uint64_t features)
25711447b59SVenkatesh Srinivas {
25811447b59SVenkatesh Srinivas 	return (VIRTIO_BUS_REINIT(device_get_parent(dev), features));
25911447b59SVenkatesh Srinivas }
26011447b59SVenkatesh Srinivas 
26111447b59SVenkatesh Srinivas void
virtio_reinit_complete(device_t dev)26211447b59SVenkatesh Srinivas virtio_reinit_complete(device_t dev)
26311447b59SVenkatesh Srinivas {
26411447b59SVenkatesh Srinivas 	VIRTIO_BUS_REINIT_COMPLETE(device_get_parent(dev));
26511447b59SVenkatesh Srinivas }
26611447b59SVenkatesh Srinivas 
26711447b59SVenkatesh Srinivas void
virtio_read_device_config(device_t dev,bus_size_t offset,void * dst,int len)26811447b59SVenkatesh Srinivas virtio_read_device_config(device_t dev, bus_size_t offset, void *dst, int len)
26911447b59SVenkatesh Srinivas {
27011447b59SVenkatesh Srinivas 	VIRTIO_BUS_READ_DEVICE_CONFIG(device_get_parent(dev),
27111447b59SVenkatesh Srinivas 				      offset, dst, len);
27211447b59SVenkatesh Srinivas }
27311447b59SVenkatesh Srinivas 
27411447b59SVenkatesh Srinivas void
virtio_write_device_config(device_t dev,bus_size_t offset,void * dst,int len)27511447b59SVenkatesh Srinivas virtio_write_device_config(device_t dev, bus_size_t offset, void *dst, int len)
27611447b59SVenkatesh Srinivas {
27711447b59SVenkatesh Srinivas 	VIRTIO_BUS_WRITE_DEVICE_CONFIG(device_get_parent(dev),
27811447b59SVenkatesh Srinivas 				       offset, dst, len);
27911447b59SVenkatesh Srinivas }
28011447b59SVenkatesh Srinivas 
28111447b59SVenkatesh Srinivas static int
virtio_modevent(module_t mod,int type,void * unused)28211447b59SVenkatesh Srinivas virtio_modevent(module_t mod, int type, void *unused)
28311447b59SVenkatesh Srinivas {
28411447b59SVenkatesh Srinivas 	int error;
28511447b59SVenkatesh Srinivas 
28611447b59SVenkatesh Srinivas 	error = 0;
28711447b59SVenkatesh Srinivas 
28811447b59SVenkatesh Srinivas 	switch (type) {
28911447b59SVenkatesh Srinivas 	case MOD_LOAD:
29011447b59SVenkatesh Srinivas 	case MOD_UNLOAD:
29111447b59SVenkatesh Srinivas 	case MOD_SHUTDOWN:
29211447b59SVenkatesh Srinivas 		break;
29311447b59SVenkatesh Srinivas 	default:
29411447b59SVenkatesh Srinivas 		error = EOPNOTSUPP;
29511447b59SVenkatesh Srinivas 		break;
29611447b59SVenkatesh Srinivas 	}
29711447b59SVenkatesh Srinivas 
29811447b59SVenkatesh Srinivas 	return (error);
29911447b59SVenkatesh Srinivas }
30011447b59SVenkatesh Srinivas 
30111447b59SVenkatesh Srinivas static moduledata_t virtio_mod = {
30211447b59SVenkatesh Srinivas 	"virtio",
30311447b59SVenkatesh Srinivas 	virtio_modevent,
30411447b59SVenkatesh Srinivas 	0
30511447b59SVenkatesh Srinivas };
30611447b59SVenkatesh Srinivas 
307*8afeec5dSMatthew Dillon DECLARE_MODULE(virtio, virtio_mod, SI_SUB_DRIVERS, SI_ORDER_EARLIER);
30811447b59SVenkatesh Srinivas MODULE_VERSION(virtio, 1);
309