kernel -- virtio: Implement virtio-layer lwkt_serializer for devices
[dragonfly.git] / sys / dev / virtual / virtio / virtio / virtio.c
1 /*-
2  * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.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  * $FreeBSD: src/sys/dev/virtio/virtio.c,v 1.1 2011/11/18 05:43:43 grehan Exp $
27  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/module.h>
34 #include <sys/sbuf.h>
35
36 #include <machine/inttypes.h>
37 #include <sys/bus.h>
38 #include <sys/serialize.h>
39 #include <sys/rman.h>
40
41 #include "virtio.h"
42 #include "virtqueue.h"
43
44 #include "virtio_if.h"
45 #include "virtio_bus_if.h"
46
47 static int virtio_modevent(module_t, int, void *);
48 static const char *virtio_feature_name(uint64_t, struct virtio_feature_desc *);
49
50 static struct virtio_ident {
51         uint16_t devid;
52         char    *name;
53 } virtio_ident_table[] = {
54         { VIRTIO_ID_NETWORK,    "Network"       },
55         { VIRTIO_ID_BLOCK,      "Block"         },
56         { VIRTIO_ID_CONSOLE,    "Console"       },
57         { VIRTIO_ID_ENTROPY,    "Entropy"       },
58         { VIRTIO_ID_BALLOON,    "Balloon"       },
59         { VIRTIO_ID_IOMEMORY,   "IOMemory"      },
60         { VIRTIO_ID_9P,         "9P Transport"  },
61
62         { 0, NULL }
63 };
64
65 /* Device independent features. */
66 static struct virtio_feature_desc virtio_common_feature_desc[] = {
67         { VIRTIO_F_NOTIFY_ON_EMPTY,     "NotifyOnEmpty" },
68         { VIRTIO_RING_F_EVENT_IDX,      "EventIdx"      },
69         { VIRTIO_F_BAD_FEATURE,         "BadFeature"    },
70
71         { 0, NULL }
72 };
73
74 const char *
75 virtio_device_name(uint16_t devid)
76 {
77         struct virtio_ident *ident;
78
79         for (ident = virtio_ident_table; ident->name != NULL; ident++) {
80                 if (ident->devid == devid)
81                         return (ident->name);
82         }
83
84         return (NULL);
85 }
86
87 int
88 virtio_get_device_type(device_t dev)
89 {
90         uintptr_t devtype;
91
92         devtype = -1;
93
94         BUS_READ_IVAR(device_get_parent(dev), dev,
95             VIRTIO_IVAR_DEVTYPE, &devtype);
96
97         return ((int) devtype);
98 }
99
100 void
101 virtio_set_feature_desc(device_t dev,
102     struct virtio_feature_desc *feature_desc)
103 {
104
105         BUS_WRITE_IVAR(device_get_parent(dev), dev,
106             VIRTIO_IVAR_FEATURE_DESC, (uintptr_t) feature_desc);
107 }
108
109 /* XXX(vsrinivas): Hmm, check this SBUF usage */
110 void
111 virtio_describe(device_t dev, const char *msg,
112     uint64_t features, struct virtio_feature_desc *feature_desc)
113 {
114         struct sbuf sb;
115         uint64_t val;
116         char *buf;
117         const char *name;
118         int n;
119
120         if ((buf = kmalloc(512, M_TEMP, M_NOWAIT)) == NULL) {
121                 device_printf(dev, "%s features: 0x%"PRIx64"\n", msg,
122                     features);
123                 return;
124         }
125
126         sbuf_new(&sb, buf, 512, SBUF_FIXEDLEN);
127         sbuf_printf(&sb, "%s features: 0x%"PRIx64, msg, features);
128
129         for (n = 0, val = 1ULL << 63; val != 0; val >>= 1) {
130                 /*
131                  * BAD_FEATURE is used to detect broken Linux clients
132                  * and therefore is not applicable to FreeBSD.
133                  */
134                 if (((features & val) == 0) || val == VIRTIO_F_BAD_FEATURE)
135                         continue;
136
137                 if (n++ == 0)
138                         sbuf_cat(&sb, " <");
139                 else
140                         sbuf_cat(&sb, ",");
141
142                 name = NULL;
143                 if (feature_desc != NULL)
144                         name = virtio_feature_name(val, feature_desc);
145                 if (name == NULL)
146                         name = virtio_feature_name(val,
147                             virtio_common_feature_desc);
148
149                 if (name == NULL)
150                         sbuf_printf(&sb, "0x%"PRIx64, val);
151                 else
152                         sbuf_cat(&sb, name);
153         }
154
155         if (n > 0)
156                 sbuf_cat(&sb, ">");
157
158        sbuf_finish(&sb);
159        if (sbuf_overflowed(&sb) == 0)
160                 device_printf(dev, "%s\n", sbuf_data(&sb));
161
162         sbuf_delete(&sb);
163         kfree(buf, M_TEMP);
164 }
165
166 static const char *
167 virtio_feature_name(uint64_t val, struct virtio_feature_desc *feature_desc)
168 {
169         int i;
170
171         for (i = 0; feature_desc[i].vfd_val != 0; i++)
172                 if (val == feature_desc[i].vfd_val)
173                         return (feature_desc[i].vfd_str);
174
175         return (NULL);
176 }
177
178 /*
179  * VirtIO bus method wrappers.
180  */
181
182 uint64_t
183 virtio_negotiate_features(device_t dev, uint64_t child_features)
184 {
185         return (VIRTIO_BUS_NEGOTIATE_FEATURES(device_get_parent(dev),
186                 child_features));
187 }
188
189 int
190 virtio_alloc_virtqueues(device_t dev, int flags, int nvqs,
191     struct vq_alloc_info *info)
192 {
193         return (VIRTIO_BUS_ALLOC_VIRTQUEUES(device_get_parent(dev), flags,
194                 nvqs, info));
195 }
196
197 int
198 virtio_setup_intr(device_t dev, lwkt_serialize_t slz)
199 {
200         return (VIRTIO_BUS_SETUP_INTR(device_get_parent(dev), slz));
201 }
202
203 int
204 virtio_with_feature(device_t dev, uint64_t feature)
205 {
206         return (VIRTIO_BUS_WITH_FEATURE(device_get_parent(dev), feature));
207 }
208
209 void
210 virtio_stop(device_t dev)
211 {
212         VIRTIO_BUS_STOP(device_get_parent(dev));
213 }
214
215 int
216 virtio_reinit(device_t dev, uint64_t features)
217 {
218         return (VIRTIO_BUS_REINIT(device_get_parent(dev), features));
219 }
220
221 void
222 virtio_reinit_complete(device_t dev)
223 {
224         VIRTIO_BUS_REINIT_COMPLETE(device_get_parent(dev));
225 }
226
227 void
228 virtio_read_device_config(device_t dev, bus_size_t offset, void *dst, int len)
229 {
230         VIRTIO_BUS_READ_DEVICE_CONFIG(device_get_parent(dev),
231                                       offset, dst, len);
232 }
233
234 void
235 virtio_write_device_config(device_t dev, bus_size_t offset, void *dst, int len)
236 {
237         VIRTIO_BUS_WRITE_DEVICE_CONFIG(device_get_parent(dev),
238                                        offset, dst, len);
239 }
240
241 static int
242 virtio_modevent(module_t mod, int type, void *unused)
243 {
244         int error;
245
246         error = 0;
247
248         switch (type) {
249         case MOD_LOAD:
250         case MOD_UNLOAD:
251         case MOD_SHUTDOWN:
252                 break;
253         default:
254                 error = EOPNOTSUPP;
255                 break;
256         }
257
258         return (error);
259 }
260
261 static moduledata_t virtio_mod = {
262         "virtio",
263         virtio_modevent,
264         0
265 };
266
267 DECLARE_MODULE(virtio, virtio_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
268 MODULE_VERSION(virtio, 1);