2 * Copyright (c) 2011 NetApp, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
40 SLIST_ENTRY(vdev) entry;
44 static SLIST_HEAD(, vdev) vdev_head;
45 static int vdev_count;
48 SLIST_ENTRY(vdev_region) entry;
53 static SLIST_HEAD(, vdev_region) region_head;
54 static int region_count;
56 static MALLOC_DEFINE(M_VDEV, "vdev", "vdev");
59 #define VDEV_RESET (1)
62 // static const char* vdev_event_str[] = {"VDEV_INIT", "VDEV_RESET", "VDEV_HALT"};
65 vdev_system_event(int event)
71 SLIST_FOREACH(vd, &vdev_head, entry) {
72 // printf("%s : %s Device %s\n", __func__, vdev_event_str[event], vd->ops->name);
75 rc = vd->ops->init(vd->dev);
78 rc = vd->ops->reset(vd->dev);
81 rc = vd->ops->halt(vd->dev);
87 printf("vdev %s init failed rc=%d\n",
98 return vdev_system_event(VDEV_INIT);
104 return vdev_system_event(VDEV_RESET);
110 return vdev_system_event(VDEV_HALT);
116 SLIST_INIT(&vdev_head);
119 SLIST_INIT(®ion_head);
123 vdev_vm_cleanup(void)
128 while (!SLIST_EMPTY(&vdev_head)) {
129 vd = SLIST_FIRST(&vdev_head);
130 SLIST_REMOVE_HEAD(&vdev_head, entry);
137 vdev_register(struct vdev_ops *ops, void *dev)
140 vd = malloc(sizeof(*vd), M_VDEV, M_WAITOK | M_ZERO);
145 SLIST_INSERT_HEAD(&vdev_head, vd, entry);
151 vdev_unregister(void *dev)
153 struct vdev *vd, *found;
157 SLIST_FOREACH(vd, &vdev_head, entry) {
158 if (vd->dev == dev) {
164 SLIST_REMOVE(&vdev_head, found, vdev, entry);
169 #define IN_RANGE(val, start, end) \
170 (((val) >= (start)) && ((val) < (end)))
172 static struct vdev_region*
173 vdev_find_region(struct io_region *io, void *dev)
175 struct vdev_region *region, *found;
176 uint64_t region_base;
182 // FIXME: we should verify we are in the context the current
183 // vcpu here as well.
184 SLIST_FOREACH(region, ®ion_head, entry) {
185 region_base = region->io->base;
186 region_end = region_base + region->io->len;
187 if (IN_RANGE(io->base, region_base, region_end) &&
188 IN_RANGE(io->base+io->len, region_base, region_end+1) &&
189 (dev && dev == region->dev)) {
198 vdev_register_region(struct vdev_ops *ops, void *dev, struct io_region *io)
200 struct vdev_region *region;
202 region = vdev_find_region(io, dev);
207 region = malloc(sizeof(*region), M_VDEV, M_WAITOK | M_ZERO);
213 SLIST_INSERT_HEAD(®ion_head, region, entry);
220 vdev_unregister_region(void *dev, struct io_region *io)
222 struct vdev_region *region;
224 region = vdev_find_region(io, dev);
227 SLIST_REMOVE(®ion_head, region, vdev_region, entry);
228 free(region, M_VDEV);
234 vdev_memrw(uint64_t gpa, opsize_t size, uint64_t *data, int read)
236 struct vdev_region *region;
244 region = vdev_find_region(&io, NULL);
248 attr = (read) ? MMIO_READ : MMIO_WRITE;
249 if (!(region->io->attr & attr))
253 rc = region->ops->memread(region->dev, gpa, size, data);
255 rc = region->ops->memwrite(region->dev, gpa, size, *data);
261 vdev_memread(uint64_t gpa, opsize_t size, uint64_t *data)
263 return vdev_memrw(gpa, size, data, 1);
267 vdev_memwrite(uint64_t gpa, opsize_t size, uint64_t data)
269 return vdev_memrw(gpa, size, &data, 0);