]> Git Repo - qemu.git/blame - tests/libqos/virtio-mmio.c
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2019-05-21' into...
[qemu.git] / tests / libqos / virtio-mmio.c
CommitLineData
0a6ed700
MM
1/*
2 * libqos virtio MMIO driver
3 *
4 * Copyright (c) 2014 Marc Marí
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 */
9
681c28a3 10#include "qemu/osdep.h"
0a6ed700
MM
11#include "libqtest.h"
12#include "libqos/virtio.h"
13#include "libqos/virtio-mmio.h"
14#include "libqos/malloc.h"
57ed038a 15#include "libqos/qgraph.h"
ee3b850a 16#include "standard-headers/linux/virtio_ring.h"
0a6ed700 17
246fc0fb 18static uint8_t qvirtio_mmio_config_readb(QVirtioDevice *d, uint64_t off)
0a6ed700 19{
57ed038a
EGE
20 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
21 return qtest_readb(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
0a6ed700
MM
22}
23
246fc0fb 24static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t off)
0a6ed700 25{
57ed038a
EGE
26 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
27 return qtest_readw(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
0a6ed700
MM
28}
29
246fc0fb 30static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t off)
0a6ed700 31{
57ed038a
EGE
32 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
33 return qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
0a6ed700
MM
34}
35
246fc0fb 36static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t off)
0a6ed700 37{
57ed038a
EGE
38 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
39 return qtest_readq(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
0a6ed700
MM
40}
41
42static uint32_t qvirtio_mmio_get_features(QVirtioDevice *d)
43{
57ed038a
EGE
44 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
45 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 0);
46 return qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_HOST_FEATURES);
0a6ed700
MM
47}
48
49static void qvirtio_mmio_set_features(QVirtioDevice *d, uint32_t features)
50{
57ed038a 51 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
0a6ed700 52 dev->features = features;
57ed038a
EGE
53 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_GUEST_FEATURES_SEL, 0);
54 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_GUEST_FEATURES, features);
0a6ed700
MM
55}
56
57static uint32_t qvirtio_mmio_get_guest_features(QVirtioDevice *d)
58{
57ed038a 59 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
0a6ed700
MM
60 return dev->features;
61}
62
63static uint8_t qvirtio_mmio_get_status(QVirtioDevice *d)
64{
57ed038a
EGE
65 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
66 return (uint8_t)qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_STATUS);
0a6ed700
MM
67}
68
69static void qvirtio_mmio_set_status(QVirtioDevice *d, uint8_t status)
70{
57ed038a
EGE
71 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
72 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_STATUS, (uint32_t)status);
0a6ed700
MM
73}
74
75static bool qvirtio_mmio_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
76{
57ed038a 77 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
0a6ed700
MM
78 uint32_t isr;
79
57ed038a 80 isr = qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 1;
0a6ed700 81 if (isr != 0) {
57ed038a 82 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 1);
0a6ed700
MM
83 return true;
84 }
85
86 return false;
87}
88
89static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d)
90{
57ed038a 91 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
0a6ed700
MM
92 uint32_t isr;
93
57ed038a 94 isr = qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 2;
0a6ed700 95 if (isr != 0) {
57ed038a 96 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 2);
0a6ed700
MM
97 return true;
98 }
99
100 return false;
101}
102
103static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index)
104{
57ed038a
EGE
105 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
106 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_SEL, (uint32_t)index);
0a6ed700 107
57ed038a 108 g_assert_cmphex(qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_PFN), ==, 0);
0a6ed700
MM
109}
110
111static uint16_t qvirtio_mmio_get_queue_size(QVirtioDevice *d)
112{
57ed038a
EGE
113 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
114 return (uint16_t)qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX);
0a6ed700
MM
115}
116
117static void qvirtio_mmio_set_queue_address(QVirtioDevice *d, uint32_t pfn)
118{
57ed038a
EGE
119 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
120 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_PFN, pfn);
0a6ed700
MM
121}
122
123static QVirtQueue *qvirtio_mmio_virtqueue_setup(QVirtioDevice *d,
124 QGuestAllocator *alloc, uint16_t index)
125{
57ed038a 126 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
0a6ed700
MM
127 QVirtQueue *vq;
128 uint64_t addr;
129
130 vq = g_malloc0(sizeof(*vq));
131 qvirtio_mmio_queue_select(d, index);
57ed038a 132 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_ALIGN, dev->page_size);
0a6ed700
MM
133
134 vq->index = index;
135 vq->size = qvirtio_mmio_get_queue_size(d);
136 vq->free_head = 0;
137 vq->num_free = vq->size;
138 vq->align = dev->page_size;
ee3b850a
SH
139 vq->indirect = (dev->features & (1u << VIRTIO_RING_F_INDIRECT_DESC)) != 0;
140 vq->event = (dev->features & (1u << VIRTIO_RING_F_EVENT_IDX)) != 0;
0a6ed700 141
57ed038a 142 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_NUM, vq->size);
0a6ed700
MM
143
144 /* Check different than 0 */
145 g_assert_cmpint(vq->size, !=, 0);
146
147 /* Check power of 2 */
148 g_assert_cmpint(vq->size & (vq->size - 1), ==, 0);
149
150 addr = guest_alloc(alloc, qvring_size(vq->size, dev->page_size));
8b898f59 151 qvring_init(dev->qts, alloc, vq, addr);
0a6ed700
MM
152 qvirtio_mmio_set_queue_address(d, vq->desc / dev->page_size);
153
154 return vq;
155}
156
f1d3b991
SH
157static void qvirtio_mmio_virtqueue_cleanup(QVirtQueue *vq,
158 QGuestAllocator *alloc)
159{
160 guest_free(alloc, vq->desc);
161 g_free(vq);
162}
163
0a6ed700
MM
164static void qvirtio_mmio_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq)
165{
57ed038a
EGE
166 QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
167 qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_NOTIFY, vq->index);
0a6ed700
MM
168}
169
170const QVirtioBus qvirtio_mmio = {
171 .config_readb = qvirtio_mmio_config_readb,
172 .config_readw = qvirtio_mmio_config_readw,
173 .config_readl = qvirtio_mmio_config_readl,
174 .config_readq = qvirtio_mmio_config_readq,
175 .get_features = qvirtio_mmio_get_features,
176 .set_features = qvirtio_mmio_set_features,
177 .get_guest_features = qvirtio_mmio_get_guest_features,
178 .get_status = qvirtio_mmio_get_status,
179 .set_status = qvirtio_mmio_set_status,
180 .get_queue_isr_status = qvirtio_mmio_get_queue_isr_status,
181 .get_config_isr_status = qvirtio_mmio_get_config_isr_status,
182 .queue_select = qvirtio_mmio_queue_select,
183 .get_queue_size = qvirtio_mmio_get_queue_size,
184 .set_queue_address = qvirtio_mmio_set_queue_address,
185 .virtqueue_setup = qvirtio_mmio_virtqueue_setup,
f1d3b991 186 .virtqueue_cleanup = qvirtio_mmio_virtqueue_cleanup,
0a6ed700
MM
187 .virtqueue_kick = qvirtio_mmio_virtqueue_kick,
188};
189
57ed038a 190static void *qvirtio_mmio_get_driver(void *obj, const char *interface)
0a6ed700 191{
57ed038a
EGE
192 QVirtioMMIODevice *virtio_mmio = obj;
193 if (!g_strcmp0(interface, "virtio-bus")) {
194 return &virtio_mmio->vdev;
195 }
196 fprintf(stderr, "%s not present in virtio-mmio\n", interface);
197 g_assert_not_reached();
198}
199
200static void qvirtio_mmio_start_hw(QOSGraphObject *obj)
201{
202 QVirtioMMIODevice *dev = (QVirtioMMIODevice *) obj;
203 qvirtio_start_device(&dev->vdev);
204}
0a6ed700 205
57ed038a
EGE
206void qvirtio_mmio_init_device(QVirtioMMIODevice *dev, QTestState *qts,
207 uint64_t addr, uint32_t page_size)
208{
209 uint32_t magic;
210 magic = qtest_readl(qts, addr + QVIRTIO_MMIO_MAGIC_VALUE);
0a6ed700
MM
211 g_assert(magic == ('v' | 'i' << 8 | 'r' << 16 | 't' << 24));
212
57ed038a 213 dev->qts = qts;
0a6ed700
MM
214 dev->addr = addr;
215 dev->page_size = page_size;
57ed038a 216 dev->vdev.device_type = qtest_readl(qts, addr + QVIRTIO_MMIO_DEVICE_ID);
6b9cdf4c 217 dev->vdev.bus = &qvirtio_mmio;
0a6ed700 218
57ed038a
EGE
219 qtest_writel(qts, addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size);
220
221 dev->obj.get_driver = qvirtio_mmio_get_driver;
222 dev->obj.start_hw = qvirtio_mmio_start_hw;
223}
0a6ed700 224
57ed038a
EGE
225static void virtio_mmio_register_nodes(void)
226{
227 qos_node_create_driver("virtio-mmio", NULL);
228 qos_node_produces("virtio-mmio", "virtio-bus");
0a6ed700 229}
57ed038a
EGE
230
231libqos_init(virtio_mmio_register_nodes);
This page took 0.27974 seconds and 4 git commands to generate.