Statistics
| Branch: | Revision:

root / hw / syborg_virtio.c @ 1a1ea6f0

History | View | Annotate | Download (9.4 kB)

1 340d96e7 Paul Brook
/*
2 340d96e7 Paul Brook
 * Virtio Syborg bindings
3 340d96e7 Paul Brook
 *
4 340d96e7 Paul Brook
 * Copyright (c) 2009 CodeSourcery
5 340d96e7 Paul Brook
 *
6 340d96e7 Paul Brook
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 340d96e7 Paul Brook
 * of this software and associated documentation files (the "Software"), to deal
8 340d96e7 Paul Brook
 * in the Software without restriction, including without limitation the rights
9 340d96e7 Paul Brook
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 340d96e7 Paul Brook
 * copies of the Software, and to permit persons to whom the Software is
11 340d96e7 Paul Brook
 * furnished to do so, subject to the following conditions:
12 340d96e7 Paul Brook
 *
13 340d96e7 Paul Brook
 * The above copyright notice and this permission notice shall be included in
14 340d96e7 Paul Brook
 * all copies or substantial portions of the Software.
15 340d96e7 Paul Brook
 *
16 340d96e7 Paul Brook
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 340d96e7 Paul Brook
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 340d96e7 Paul Brook
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 340d96e7 Paul Brook
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 340d96e7 Paul Brook
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 340d96e7 Paul Brook
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 340d96e7 Paul Brook
 * THE SOFTWARE.
23 340d96e7 Paul Brook
 */
24 340d96e7 Paul Brook
25 340d96e7 Paul Brook
#include "syborg.h"
26 340d96e7 Paul Brook
#include "sysbus.h"
27 340d96e7 Paul Brook
#include "virtio.h"
28 8172539d Michael S. Tsirkin
#include "virtio-net.h"
29 340d96e7 Paul Brook
#include "sysemu.h"
30 340d96e7 Paul Brook
31 340d96e7 Paul Brook
//#define DEBUG_SYBORG_VIRTIO
32 340d96e7 Paul Brook
33 340d96e7 Paul Brook
#ifdef DEBUG_SYBORG_VIRTIO
34 340d96e7 Paul Brook
#define DPRINTF(fmt, ...) \
35 340d96e7 Paul Brook
do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
36 340d96e7 Paul Brook
#define BADF(fmt, ...) \
37 340d96e7 Paul Brook
do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__); \
38 340d96e7 Paul Brook
    exit(1);} while (0)
39 340d96e7 Paul Brook
#else
40 340d96e7 Paul Brook
#define DPRINTF(fmt, ...) do {} while(0)
41 340d96e7 Paul Brook
#define BADF(fmt, ...) \
42 340d96e7 Paul Brook
do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
43 340d96e7 Paul Brook
#endif
44 340d96e7 Paul Brook
45 340d96e7 Paul Brook
enum {
46 340d96e7 Paul Brook
    SYBORG_VIRTIO_ID             = 0,
47 340d96e7 Paul Brook
    SYBORG_VIRTIO_DEVTYPE        = 1,
48 340d96e7 Paul Brook
    SYBORG_VIRTIO_HOST_FEATURES  = 2,
49 340d96e7 Paul Brook
    SYBORG_VIRTIO_GUEST_FEATURES = 3,
50 340d96e7 Paul Brook
    SYBORG_VIRTIO_QUEUE_BASE     = 4,
51 340d96e7 Paul Brook
    SYBORG_VIRTIO_QUEUE_NUM      = 5,
52 340d96e7 Paul Brook
    SYBORG_VIRTIO_QUEUE_SEL      = 6,
53 340d96e7 Paul Brook
    SYBORG_VIRTIO_QUEUE_NOTIFY   = 7,
54 340d96e7 Paul Brook
    SYBORG_VIRTIO_STATUS         = 8,
55 340d96e7 Paul Brook
    SYBORG_VIRTIO_INT_ENABLE     = 9,
56 340d96e7 Paul Brook
    SYBORG_VIRTIO_INT_STATUS     = 10
57 340d96e7 Paul Brook
};
58 340d96e7 Paul Brook
59 340d96e7 Paul Brook
#define SYBORG_VIRTIO_CONFIG 0x100
60 340d96e7 Paul Brook
61 340d96e7 Paul Brook
/* Device independent interface.  */
62 340d96e7 Paul Brook
63 340d96e7 Paul Brook
typedef struct {
64 340d96e7 Paul Brook
    SysBusDevice busdev;
65 340d96e7 Paul Brook
    VirtIODevice *vdev;
66 340d96e7 Paul Brook
    qemu_irq irq;
67 340d96e7 Paul Brook
    uint32_t int_enable;
68 340d96e7 Paul Brook
    uint32_t id;
69 97b15621 Gerd Hoffmann
    NICConf nic;
70 8172539d Michael S. Tsirkin
    uint32_t host_features;
71 f0c07c7c Alex Williamson
    virtio_net_conf net;
72 340d96e7 Paul Brook
} SyborgVirtIOProxy;
73 340d96e7 Paul Brook
74 c227f099 Anthony Liguori
static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
75 340d96e7 Paul Brook
{
76 340d96e7 Paul Brook
    SyborgVirtIOProxy *s = opaque;
77 340d96e7 Paul Brook
    VirtIODevice *vdev = s->vdev;
78 340d96e7 Paul Brook
    uint32_t ret;
79 340d96e7 Paul Brook
80 340d96e7 Paul Brook
    DPRINTF("readl 0x%x\n", (int)offset);
81 340d96e7 Paul Brook
    if (offset >= SYBORG_VIRTIO_CONFIG) {
82 340d96e7 Paul Brook
        return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
83 340d96e7 Paul Brook
    }
84 340d96e7 Paul Brook
    switch(offset >> 2) {
85 340d96e7 Paul Brook
    case SYBORG_VIRTIO_ID:
86 340d96e7 Paul Brook
        ret = SYBORG_ID_VIRTIO;
87 340d96e7 Paul Brook
        break;
88 340d96e7 Paul Brook
    case SYBORG_VIRTIO_DEVTYPE:
89 340d96e7 Paul Brook
        ret = s->id;
90 340d96e7 Paul Brook
        break;
91 340d96e7 Paul Brook
    case SYBORG_VIRTIO_HOST_FEATURES:
92 8172539d Michael S. Tsirkin
        ret = s->host_features;
93 340d96e7 Paul Brook
        break;
94 340d96e7 Paul Brook
    case SYBORG_VIRTIO_GUEST_FEATURES:
95 704a76fc Michael S. Tsirkin
        ret = vdev->guest_features;
96 340d96e7 Paul Brook
        break;
97 340d96e7 Paul Brook
    case SYBORG_VIRTIO_QUEUE_BASE:
98 340d96e7 Paul Brook
        ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
99 340d96e7 Paul Brook
        break;
100 340d96e7 Paul Brook
    case SYBORG_VIRTIO_QUEUE_NUM:
101 340d96e7 Paul Brook
        ret = virtio_queue_get_num(vdev, vdev->queue_sel);
102 340d96e7 Paul Brook
        break;
103 340d96e7 Paul Brook
    case SYBORG_VIRTIO_QUEUE_SEL:
104 340d96e7 Paul Brook
        ret = vdev->queue_sel;
105 340d96e7 Paul Brook
        break;
106 340d96e7 Paul Brook
    case SYBORG_VIRTIO_STATUS:
107 340d96e7 Paul Brook
        ret = vdev->status;
108 340d96e7 Paul Brook
        break;
109 340d96e7 Paul Brook
    case SYBORG_VIRTIO_INT_ENABLE:
110 340d96e7 Paul Brook
        ret = s->int_enable;
111 340d96e7 Paul Brook
        break;
112 340d96e7 Paul Brook
    case SYBORG_VIRTIO_INT_STATUS:
113 340d96e7 Paul Brook
        ret = vdev->isr;
114 340d96e7 Paul Brook
        break;
115 340d96e7 Paul Brook
    default:
116 340d96e7 Paul Brook
        BADF("Bad read offset 0x%x\n", (int)offset);
117 340d96e7 Paul Brook
        return 0;
118 340d96e7 Paul Brook
    }
119 340d96e7 Paul Brook
    return ret;
120 340d96e7 Paul Brook
}
121 340d96e7 Paul Brook
122 c227f099 Anthony Liguori
static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
123 340d96e7 Paul Brook
                                 uint32_t value)
124 340d96e7 Paul Brook
{
125 340d96e7 Paul Brook
    SyborgVirtIOProxy *s = opaque;
126 340d96e7 Paul Brook
    VirtIODevice *vdev = s->vdev;
127 340d96e7 Paul Brook
128 340d96e7 Paul Brook
    DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
129 340d96e7 Paul Brook
    if (offset >= SYBORG_VIRTIO_CONFIG) {
130 340d96e7 Paul Brook
        return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
131 340d96e7 Paul Brook
                                    value);
132 340d96e7 Paul Brook
    }
133 340d96e7 Paul Brook
    switch (offset >> 2) {
134 340d96e7 Paul Brook
    case SYBORG_VIRTIO_GUEST_FEATURES:
135 340d96e7 Paul Brook
        if (vdev->set_features)
136 340d96e7 Paul Brook
            vdev->set_features(vdev, value);
137 704a76fc Michael S. Tsirkin
        vdev->guest_features = value;
138 340d96e7 Paul Brook
        break;
139 340d96e7 Paul Brook
    case SYBORG_VIRTIO_QUEUE_BASE:
140 7055e687 Michael S. Tsirkin
        if (value == 0)
141 7055e687 Michael S. Tsirkin
            virtio_reset(vdev);
142 7055e687 Michael S. Tsirkin
        else
143 7055e687 Michael S. Tsirkin
            virtio_queue_set_addr(vdev, vdev->queue_sel, value);
144 340d96e7 Paul Brook
        break;
145 340d96e7 Paul Brook
    case SYBORG_VIRTIO_QUEUE_SEL:
146 340d96e7 Paul Brook
        if (value < VIRTIO_PCI_QUEUE_MAX)
147 340d96e7 Paul Brook
            vdev->queue_sel = value;
148 340d96e7 Paul Brook
        break;
149 340d96e7 Paul Brook
    case SYBORG_VIRTIO_QUEUE_NOTIFY:
150 340d96e7 Paul Brook
        virtio_queue_notify(vdev, value);
151 340d96e7 Paul Brook
        break;
152 340d96e7 Paul Brook
    case SYBORG_VIRTIO_STATUS:
153 3e607cb5 Michael S. Tsirkin
        virtio_set_status(vdev, value & 0xFF);
154 340d96e7 Paul Brook
        if (vdev->status == 0)
155 340d96e7 Paul Brook
            virtio_reset(vdev);
156 340d96e7 Paul Brook
        break;
157 340d96e7 Paul Brook
    case SYBORG_VIRTIO_INT_ENABLE:
158 340d96e7 Paul Brook
        s->int_enable = value;
159 340d96e7 Paul Brook
        virtio_update_irq(vdev);
160 340d96e7 Paul Brook
        break;
161 340d96e7 Paul Brook
    case SYBORG_VIRTIO_INT_STATUS:
162 340d96e7 Paul Brook
        vdev->isr &= ~value;
163 340d96e7 Paul Brook
        virtio_update_irq(vdev);
164 340d96e7 Paul Brook
        break;
165 340d96e7 Paul Brook
    default:
166 340d96e7 Paul Brook
        BADF("Bad write offset 0x%x\n", (int)offset);
167 340d96e7 Paul Brook
        break;
168 340d96e7 Paul Brook
    }
169 340d96e7 Paul Brook
}
170 340d96e7 Paul Brook
171 c227f099 Anthony Liguori
static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
172 340d96e7 Paul Brook
{
173 340d96e7 Paul Brook
    SyborgVirtIOProxy *s = opaque;
174 340d96e7 Paul Brook
    VirtIODevice *vdev = s->vdev;
175 340d96e7 Paul Brook
176 340d96e7 Paul Brook
    DPRINTF("readw 0x%x\n", (int)offset);
177 340d96e7 Paul Brook
    if (offset >= SYBORG_VIRTIO_CONFIG) {
178 340d96e7 Paul Brook
        return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
179 340d96e7 Paul Brook
    }
180 340d96e7 Paul Brook
    BADF("Bad halfword read offset 0x%x\n", (int)offset);
181 340d96e7 Paul Brook
    return -1;
182 340d96e7 Paul Brook
}
183 340d96e7 Paul Brook
184 c227f099 Anthony Liguori
static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
185 340d96e7 Paul Brook
                                 uint32_t value)
186 340d96e7 Paul Brook
{
187 340d96e7 Paul Brook
    SyborgVirtIOProxy *s = opaque;
188 340d96e7 Paul Brook
    VirtIODevice *vdev = s->vdev;
189 340d96e7 Paul Brook
190 340d96e7 Paul Brook
    DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
191 340d96e7 Paul Brook
    if (offset >= SYBORG_VIRTIO_CONFIG) {
192 340d96e7 Paul Brook
        return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
193 340d96e7 Paul Brook
                                    value);
194 340d96e7 Paul Brook
    }
195 340d96e7 Paul Brook
    BADF("Bad halfword write offset 0x%x\n", (int)offset);
196 340d96e7 Paul Brook
}
197 340d96e7 Paul Brook
198 c227f099 Anthony Liguori
static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
199 340d96e7 Paul Brook
{
200 340d96e7 Paul Brook
    SyborgVirtIOProxy *s = opaque;
201 340d96e7 Paul Brook
    VirtIODevice *vdev = s->vdev;
202 340d96e7 Paul Brook
203 340d96e7 Paul Brook
    DPRINTF("readb 0x%x\n", (int)offset);
204 340d96e7 Paul Brook
    if (offset >= SYBORG_VIRTIO_CONFIG) {
205 340d96e7 Paul Brook
        return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
206 340d96e7 Paul Brook
    }
207 340d96e7 Paul Brook
    BADF("Bad byte read offset 0x%x\n", (int)offset);
208 340d96e7 Paul Brook
    return -1;
209 340d96e7 Paul Brook
}
210 340d96e7 Paul Brook
211 c227f099 Anthony Liguori
static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
212 340d96e7 Paul Brook
                                 uint32_t value)
213 340d96e7 Paul Brook
{
214 340d96e7 Paul Brook
    SyborgVirtIOProxy *s = opaque;
215 340d96e7 Paul Brook
    VirtIODevice *vdev = s->vdev;
216 340d96e7 Paul Brook
217 340d96e7 Paul Brook
    DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
218 340d96e7 Paul Brook
    if (offset >= SYBORG_VIRTIO_CONFIG) {
219 340d96e7 Paul Brook
        return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
220 340d96e7 Paul Brook
                                    value);
221 340d96e7 Paul Brook
    }
222 340d96e7 Paul Brook
    BADF("Bad byte write offset 0x%x\n", (int)offset);
223 340d96e7 Paul Brook
}
224 340d96e7 Paul Brook
225 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
226 340d96e7 Paul Brook
     syborg_virtio_readb,
227 340d96e7 Paul Brook
     syborg_virtio_readw,
228 340d96e7 Paul Brook
     syborg_virtio_readl
229 340d96e7 Paul Brook
};
230 340d96e7 Paul Brook
231 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
232 340d96e7 Paul Brook
     syborg_virtio_writeb,
233 340d96e7 Paul Brook
     syborg_virtio_writew,
234 340d96e7 Paul Brook
     syborg_virtio_writel
235 340d96e7 Paul Brook
};
236 340d96e7 Paul Brook
237 7055e687 Michael S. Tsirkin
static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
238 340d96e7 Paul Brook
{
239 340d96e7 Paul Brook
    SyborgVirtIOProxy *proxy = opaque;
240 340d96e7 Paul Brook
    int level;
241 340d96e7 Paul Brook
242 340d96e7 Paul Brook
    level = proxy->int_enable & proxy->vdev->isr;
243 340d96e7 Paul Brook
    DPRINTF("IRQ %d\n", level);
244 340d96e7 Paul Brook
    qemu_set_irq(proxy->irq, level != 0);
245 340d96e7 Paul Brook
}
246 340d96e7 Paul Brook
247 6d74ca5a Michael S. Tsirkin
static unsigned syborg_virtio_get_features(void *opaque)
248 6d74ca5a Michael S. Tsirkin
{
249 8172539d Michael S. Tsirkin
    SyborgVirtIOProxy *proxy = opaque;
250 8172539d Michael S. Tsirkin
    return proxy->host_features;
251 6d74ca5a Michael S. Tsirkin
}
252 6d74ca5a Michael S. Tsirkin
253 340d96e7 Paul Brook
static VirtIOBindings syborg_virtio_bindings = {
254 6d74ca5a Michael S. Tsirkin
    .notify = syborg_virtio_update_irq,
255 6d74ca5a Michael S. Tsirkin
    .get_features = syborg_virtio_get_features,
256 340d96e7 Paul Brook
};
257 340d96e7 Paul Brook
258 81a322d4 Gerd Hoffmann
static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
259 340d96e7 Paul Brook
{
260 340d96e7 Paul Brook
    int iomemtype;
261 340d96e7 Paul Brook
262 340d96e7 Paul Brook
    proxy->vdev = vdev;
263 340d96e7 Paul Brook
264 7055e687 Michael S. Tsirkin
    /* Don't support multiple vectors */
265 7055e687 Michael S. Tsirkin
    proxy->vdev->nvectors = 0;
266 340d96e7 Paul Brook
    sysbus_init_irq(&proxy->busdev, &proxy->irq);
267 1eed09cb Avi Kivity
    iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
268 340d96e7 Paul Brook
                                       syborg_virtio_writefn, proxy);
269 340d96e7 Paul Brook
    sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
270 340d96e7 Paul Brook
271 340d96e7 Paul Brook
    proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
272 340d96e7 Paul Brook
273 a08d4367 Jan Kiszka
    qemu_register_reset(virtio_reset, vdev);
274 7055e687 Michael S. Tsirkin
275 340d96e7 Paul Brook
    virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
276 8172539d Michael S. Tsirkin
    proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
277 8172539d Michael S. Tsirkin
    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
278 81a322d4 Gerd Hoffmann
    return 0;
279 340d96e7 Paul Brook
}
280 340d96e7 Paul Brook
281 340d96e7 Paul Brook
/* Device specific bindings.  */
282 340d96e7 Paul Brook
283 81a322d4 Gerd Hoffmann
static int syborg_virtio_net_init(SysBusDevice *dev)
284 340d96e7 Paul Brook
{
285 340d96e7 Paul Brook
    VirtIODevice *vdev;
286 340d96e7 Paul Brook
    SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
287 340d96e7 Paul Brook
288 f0c07c7c Alex Williamson
    vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
289 81a322d4 Gerd Hoffmann
    return syborg_virtio_init(proxy, vdev);
290 340d96e7 Paul Brook
}
291 340d96e7 Paul Brook
292 97b15621 Gerd Hoffmann
static SysBusDeviceInfo syborg_virtio_net_info = {
293 97b15621 Gerd Hoffmann
    .init = syborg_virtio_net_init,
294 97b15621 Gerd Hoffmann
    .qdev.name  = "syborg,virtio-net",
295 97b15621 Gerd Hoffmann
    .qdev.size  = sizeof(SyborgVirtIOProxy),
296 97b15621 Gerd Hoffmann
    .qdev.props = (Property[]) {
297 97b15621 Gerd Hoffmann
        DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
298 8172539d Michael S. Tsirkin
        DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
299 f0c07c7c Alex Williamson
        DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
300 f0c07c7c Alex Williamson
                           net.txtimer, TX_TIMER_INTERVAL),
301 e3f30488 Alex Williamson
        DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
302 e3f30488 Alex Williamson
                          net.txburst, TX_BURST),
303 a697a334 Alex Williamson
        DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
304 97b15621 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
305 97b15621 Gerd Hoffmann
    }
306 97b15621 Gerd Hoffmann
};
307 97b15621 Gerd Hoffmann
308 340d96e7 Paul Brook
static void syborg_virtio_register_devices(void)
309 340d96e7 Paul Brook
{
310 97b15621 Gerd Hoffmann
    sysbus_register_withprop(&syborg_virtio_net_info);
311 340d96e7 Paul Brook
}
312 340d96e7 Paul Brook
313 340d96e7 Paul Brook
device_init(syborg_virtio_register_devices)