1336f459cSPeter Grehan /*-
27282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause
37282444bSPedro F. Giffuni *
49a732166SBryan Venteicher * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org>
59a732166SBryan Venteicher * All rights reserved.
610b59a9bSPeter Grehan *
7336f459cSPeter Grehan * Redistribution and use in source and binary forms, with or without
8336f459cSPeter Grehan * modification, are permitted provided that the following conditions
9336f459cSPeter Grehan * are met:
10336f459cSPeter Grehan * 1. Redistributions of source code must retain the above copyright
119a732166SBryan Venteicher * notice unmodified, this list of conditions, and the following
129a732166SBryan Venteicher * disclaimer.
13336f459cSPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright
14336f459cSPeter Grehan * notice, this list of conditions and the following disclaimer in the
15336f459cSPeter Grehan * documentation and/or other materials provided with the distribution.
169a732166SBryan Venteicher *
179a732166SBryan Venteicher * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189a732166SBryan Venteicher * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199a732166SBryan Venteicher * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209a732166SBryan Venteicher * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219a732166SBryan Venteicher * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229a732166SBryan Venteicher * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239a732166SBryan Venteicher * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249a732166SBryan Venteicher * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259a732166SBryan Venteicher * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269a732166SBryan Venteicher * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710b59a9bSPeter Grehan */
2810b59a9bSPeter Grehan
2910b59a9bSPeter Grehan #ifndef _VIRTIO_H_
3010b59a9bSPeter Grehan #define _VIRTIO_H_
3110b59a9bSPeter Grehan
329da9560cSBryan Venteicher #include <dev/virtio/virtio_endian.h>
339a732166SBryan Venteicher #include <dev/virtio/virtio_ids.h>
3445543f07SBryan Venteicher #include <dev/virtio/virtio_config.h>
359a732166SBryan Venteicher
3654ac6f72SKa Ho Ng #ifdef _KERNEL
3754ac6f72SKa Ho Ng
38703f17d6SBryan Venteicher struct sbuf;
3910b59a9bSPeter Grehan struct vq_alloc_info;
4010b59a9bSPeter Grehan
4110b59a9bSPeter Grehan /*
4210b59a9bSPeter Grehan * Each virtqueue indirect descriptor list must be physically contiguous.
4310b59a9bSPeter Grehan * To allow us to malloc(9) each list individually, limit the number
4410b59a9bSPeter Grehan * supported to what will fit in one page. With 4KB pages, this is a limit
4510b59a9bSPeter Grehan * of 256 descriptors. If there is ever a need for more, we can switch to
4610b59a9bSPeter Grehan * contigmalloc(9) for the larger allocations, similar to what
4710b59a9bSPeter Grehan * bus_dmamem_alloc(9) does.
4810b59a9bSPeter Grehan *
4910b59a9bSPeter Grehan * Note the sizeof(struct vring_desc) is 16 bytes.
5010b59a9bSPeter Grehan */
5110b59a9bSPeter Grehan #define VIRTIO_MAX_INDIRECT ((int) (PAGE_SIZE / 16))
5210b59a9bSPeter Grehan
5310b59a9bSPeter Grehan /*
5410b59a9bSPeter Grehan * VirtIO instance variables indices.
5510b59a9bSPeter Grehan */
5610b59a9bSPeter Grehan #define VIRTIO_IVAR_DEVTYPE 1
5710b59a9bSPeter Grehan #define VIRTIO_IVAR_FEATURE_DESC 2
58310dacd0SPeter Grehan #define VIRTIO_IVAR_VENDOR 3
59310dacd0SPeter Grehan #define VIRTIO_IVAR_DEVICE 4
60310dacd0SPeter Grehan #define VIRTIO_IVAR_SUBVENDOR 5
61310dacd0SPeter Grehan #define VIRTIO_IVAR_SUBDEVICE 6
629da9560cSBryan Venteicher #define VIRTIO_IVAR_MODERN 7
6310b59a9bSPeter Grehan
6410b59a9bSPeter Grehan struct virtio_feature_desc {
6510b59a9bSPeter Grehan uint64_t vfd_val;
66abd6790cSBryan Venteicher const char *vfd_str;
6710b59a9bSPeter Grehan };
6810b59a9bSPeter Grehan
695c4c96d3SJohn Baldwin #define VIRTIO_DRIVER_MODULE(name, driver, evh, arg) \
705c4c96d3SJohn Baldwin DRIVER_MODULE(name, virtio_mmio, driver, evh, arg); \
715c4c96d3SJohn Baldwin DRIVER_MODULE(name, virtio_pci, driver, evh, arg)
72633218eeSJessica Clarke
730f6040f0SConrad Meyer struct virtio_pnp_match {
740f6040f0SConrad Meyer uint32_t device_type;
750f6040f0SConrad Meyer const char *description;
760f6040f0SConrad Meyer };
77633218eeSJessica Clarke #define VIRTIO_SIMPLE_PNPINFO(driver, devtype, desc) \
780f6040f0SConrad Meyer static const struct virtio_pnp_match driver ## _match = { \
790f6040f0SConrad Meyer .device_type = devtype, \
800f6040f0SConrad Meyer .description = desc, \
81633218eeSJessica Clarke }; \
82633218eeSJessica Clarke MODULE_PNP_INFO("U32:device_type;D:#", virtio_mmio, driver, \
83633218eeSJessica Clarke &driver ## _match, 1); \
84633218eeSJessica Clarke MODULE_PNP_INFO("U32:device_type;D:#", virtio_pci, driver, \
850f6040f0SConrad Meyer &driver ## _match, 1)
860f6040f0SConrad Meyer #define VIRTIO_SIMPLE_PROBE(dev, driver) \
870f6040f0SConrad Meyer (virtio_simple_probe(dev, &driver ## _match))
880f6040f0SConrad Meyer
8910b59a9bSPeter Grehan const char *virtio_device_name(uint16_t devid);
9010b59a9bSPeter Grehan void virtio_describe(device_t dev, const char *msg,
91703f17d6SBryan Venteicher uint64_t features, struct virtio_feature_desc *desc);
92703f17d6SBryan Venteicher int virtio_describe_sbuf(struct sbuf *sb, uint64_t features,
93703f17d6SBryan Venteicher struct virtio_feature_desc *desc);
949da9560cSBryan Venteicher uint64_t virtio_filter_transport_features(uint64_t features);
95ccb576a8SMina Galić bool virtio_bus_is_modern(device_t dev);
969da9560cSBryan Venteicher void virtio_read_device_config_array(device_t dev, bus_size_t offset,
979da9560cSBryan Venteicher void *dst, int size, int count);
9810b59a9bSPeter Grehan
9910b59a9bSPeter Grehan /*
10010b59a9bSPeter Grehan * VirtIO Bus Methods.
10110b59a9bSPeter Grehan */
102310dacd0SPeter Grehan void virtio_read_ivar(device_t dev, int ivar, uintptr_t *val);
103310dacd0SPeter Grehan void virtio_write_ivar(device_t dev, int ivar, uintptr_t val);
10410b59a9bSPeter Grehan uint64_t virtio_negotiate_features(device_t dev, uint64_t child_features);
1059da9560cSBryan Venteicher int virtio_finalize_features(device_t dev);
106*180c0240SMina Galić int virtio_alloc_virtqueues(device_t dev, int nvqs,
10710b59a9bSPeter Grehan struct vq_alloc_info *info);
10810b59a9bSPeter Grehan int virtio_setup_intr(device_t dev, enum intr_type type);
109ccb576a8SMina Galić bool virtio_with_feature(device_t dev, uint64_t feature);
11010b59a9bSPeter Grehan void virtio_stop(device_t dev);
111985ed053SBryan Venteicher int virtio_config_generation(device_t dev);
11210b59a9bSPeter Grehan int virtio_reinit(device_t dev, uint64_t features);
11310b59a9bSPeter Grehan void virtio_reinit_complete(device_t dev);
114ddfc9c4cSWarner Losh int virtio_child_pnpinfo(device_t busdev, device_t child, struct sbuf *sb);
11510b59a9bSPeter Grehan
11610b59a9bSPeter Grehan /*
11710b59a9bSPeter Grehan * Read/write a variable amount from the device specific (ie, network)
11810b59a9bSPeter Grehan * configuration region. This region is encoded in the same endian as
11910b59a9bSPeter Grehan * the guest.
12010b59a9bSPeter Grehan */
12110b59a9bSPeter Grehan void virtio_read_device_config(device_t dev, bus_size_t offset,
12210b59a9bSPeter Grehan void *dst, int length);
12310b59a9bSPeter Grehan void virtio_write_device_config(device_t dev, bus_size_t offset,
1246c4f9516SAlex Richardson const void *src, int length);
12510b59a9bSPeter Grehan
12610b59a9bSPeter Grehan /* Inlined device specific read/write functions for common lengths. */
12710b59a9bSPeter Grehan #define VIRTIO_RDWR_DEVICE_CONFIG(size, type) \
12810b59a9bSPeter Grehan static inline type \
12910b59a9bSPeter Grehan __CONCAT(virtio_read_dev_config_,size)(device_t dev, \
13010b59a9bSPeter Grehan bus_size_t offset) \
13110b59a9bSPeter Grehan { \
13210b59a9bSPeter Grehan type val; \
13310b59a9bSPeter Grehan virtio_read_device_config(dev, offset, &val, sizeof(type)); \
13410b59a9bSPeter Grehan return (val); \
13510b59a9bSPeter Grehan } \
13610b59a9bSPeter Grehan \
13710b59a9bSPeter Grehan static inline void \
13810b59a9bSPeter Grehan __CONCAT(virtio_write_dev_config_,size)(device_t dev, \
13910b59a9bSPeter Grehan bus_size_t offset, type val) \
14010b59a9bSPeter Grehan { \
14110b59a9bSPeter Grehan virtio_write_device_config(dev, offset, &val, sizeof(type)); \
14210b59a9bSPeter Grehan }
14310b59a9bSPeter Grehan
14410b59a9bSPeter Grehan VIRTIO_RDWR_DEVICE_CONFIG(1, uint8_t);
14510b59a9bSPeter Grehan VIRTIO_RDWR_DEVICE_CONFIG(2, uint16_t);
14610b59a9bSPeter Grehan VIRTIO_RDWR_DEVICE_CONFIG(4, uint32_t);
14710b59a9bSPeter Grehan
14860ff3342SPeter Grehan #undef VIRTIO_RDWR_DEVICE_CONFIG
14960ff3342SPeter Grehan
150310dacd0SPeter Grehan #define VIRTIO_READ_IVAR(name, ivar) \
151310dacd0SPeter Grehan static inline int \
152310dacd0SPeter Grehan __CONCAT(virtio_get_,name)(device_t dev) \
153310dacd0SPeter Grehan { \
154310dacd0SPeter Grehan uintptr_t val; \
155310dacd0SPeter Grehan virtio_read_ivar(dev, ivar, &val); \
156310dacd0SPeter Grehan return ((int) val); \
157310dacd0SPeter Grehan }
158310dacd0SPeter Grehan
159310dacd0SPeter Grehan VIRTIO_READ_IVAR(device_type, VIRTIO_IVAR_DEVTYPE);
160310dacd0SPeter Grehan VIRTIO_READ_IVAR(vendor, VIRTIO_IVAR_VENDOR);
161310dacd0SPeter Grehan VIRTIO_READ_IVAR(device, VIRTIO_IVAR_DEVICE);
162310dacd0SPeter Grehan VIRTIO_READ_IVAR(subvendor, VIRTIO_IVAR_SUBVENDOR);
163310dacd0SPeter Grehan VIRTIO_READ_IVAR(subdevice, VIRTIO_IVAR_SUBDEVICE);
1649da9560cSBryan Venteicher VIRTIO_READ_IVAR(modern, VIRTIO_IVAR_MODERN);
165310dacd0SPeter Grehan
16660ff3342SPeter Grehan #undef VIRTIO_READ_IVAR
16760ff3342SPeter Grehan
168310dacd0SPeter Grehan #define VIRTIO_WRITE_IVAR(name, ivar) \
169310dacd0SPeter Grehan static inline void \
170310dacd0SPeter Grehan __CONCAT(virtio_set_,name)(device_t dev, void *val) \
171310dacd0SPeter Grehan { \
172310dacd0SPeter Grehan virtio_write_ivar(dev, ivar, (uintptr_t) val); \
173310dacd0SPeter Grehan }
174310dacd0SPeter Grehan
175310dacd0SPeter Grehan VIRTIO_WRITE_IVAR(feature_desc, VIRTIO_IVAR_FEATURE_DESC);
176310dacd0SPeter Grehan
17760ff3342SPeter Grehan #undef VIRTIO_WRITE_IVAR
17860ff3342SPeter Grehan
1790f6040f0SConrad Meyer static inline int
virtio_simple_probe(device_t dev,const struct virtio_pnp_match * match)1800f6040f0SConrad Meyer virtio_simple_probe(device_t dev, const struct virtio_pnp_match *match)
1810f6040f0SConrad Meyer {
1820f6040f0SConrad Meyer
1830f6040f0SConrad Meyer if (virtio_get_device_type(dev) != match->device_type)
1840f6040f0SConrad Meyer return (ENXIO);
1850f6040f0SConrad Meyer device_set_desc(dev, match->description);
1860f6040f0SConrad Meyer return (BUS_PROBE_DEFAULT);
1870f6040f0SConrad Meyer }
1880f6040f0SConrad Meyer
18954ac6f72SKa Ho Ng #endif /* _KERNEL */
19054ac6f72SKa Ho Ng
19110b59a9bSPeter Grehan #endif /* _VIRTIO_H_ */
192