Statistics
| Branch: | Revision:

root / hw / syborg_virtio.c @ 8c269b54

History | View | Annotate | Download (9.4 kB)

1
/*
2
 * Virtio Syborg bindings
3
 *
4
 * Copyright (c) 2009 CodeSourcery
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
#include "syborg.h"
26
#include "sysbus.h"
27
#include "virtio.h"
28
#include "virtio-net.h"
29
#include "sysemu.h"
30

    
31
//#define DEBUG_SYBORG_VIRTIO
32

    
33
#ifdef DEBUG_SYBORG_VIRTIO
34
#define DPRINTF(fmt, ...) \
35
do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
36
#define BADF(fmt, ...) \
37
do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__); \
38
    exit(1);} while (0)
39
#else
40
#define DPRINTF(fmt, ...) do {} while(0)
41
#define BADF(fmt, ...) \
42
do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
43
#endif
44

    
45
enum {
46
    SYBORG_VIRTIO_ID             = 0,
47
    SYBORG_VIRTIO_DEVTYPE        = 1,
48
    SYBORG_VIRTIO_HOST_FEATURES  = 2,
49
    SYBORG_VIRTIO_GUEST_FEATURES = 3,
50
    SYBORG_VIRTIO_QUEUE_BASE     = 4,
51
    SYBORG_VIRTIO_QUEUE_NUM      = 5,
52
    SYBORG_VIRTIO_QUEUE_SEL      = 6,
53
    SYBORG_VIRTIO_QUEUE_NOTIFY   = 7,
54
    SYBORG_VIRTIO_STATUS         = 8,
55
    SYBORG_VIRTIO_INT_ENABLE     = 9,
56
    SYBORG_VIRTIO_INT_STATUS     = 10
57
};
58

    
59
#define SYBORG_VIRTIO_CONFIG 0x100
60

    
61
/* Device independent interface.  */
62

    
63
typedef struct {
64
    SysBusDevice busdev;
65
    VirtIODevice *vdev;
66
    qemu_irq irq;
67
    uint32_t int_enable;
68
    uint32_t id;
69
    NICConf nic;
70
    uint32_t host_features;
71
    virtio_net_conf net;
72
} SyborgVirtIOProxy;
73

    
74
static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
75
{
76
    SyborgVirtIOProxy *s = opaque;
77
    VirtIODevice *vdev = s->vdev;
78
    uint32_t ret;
79

    
80
    DPRINTF("readl 0x%x\n", (int)offset);
81
    if (offset >= SYBORG_VIRTIO_CONFIG) {
82
        return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
83
    }
84
    switch(offset >> 2) {
85
    case SYBORG_VIRTIO_ID:
86
        ret = SYBORG_ID_VIRTIO;
87
        break;
88
    case SYBORG_VIRTIO_DEVTYPE:
89
        ret = s->id;
90
        break;
91
    case SYBORG_VIRTIO_HOST_FEATURES:
92
        ret = s->host_features;
93
        break;
94
    case SYBORG_VIRTIO_GUEST_FEATURES:
95
        ret = vdev->guest_features;
96
        break;
97
    case SYBORG_VIRTIO_QUEUE_BASE:
98
        ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
99
        break;
100
    case SYBORG_VIRTIO_QUEUE_NUM:
101
        ret = virtio_queue_get_num(vdev, vdev->queue_sel);
102
        break;
103
    case SYBORG_VIRTIO_QUEUE_SEL:
104
        ret = vdev->queue_sel;
105
        break;
106
    case SYBORG_VIRTIO_STATUS:
107
        ret = vdev->status;
108
        break;
109
    case SYBORG_VIRTIO_INT_ENABLE:
110
        ret = s->int_enable;
111
        break;
112
    case SYBORG_VIRTIO_INT_STATUS:
113
        ret = vdev->isr;
114
        break;
115
    default:
116
        BADF("Bad read offset 0x%x\n", (int)offset);
117
        return 0;
118
    }
119
    return ret;
120
}
121

    
122
static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
123
                                 uint32_t value)
124
{
125
    SyborgVirtIOProxy *s = opaque;
126
    VirtIODevice *vdev = s->vdev;
127

    
128
    DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
129
    if (offset >= SYBORG_VIRTIO_CONFIG) {
130
        return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
131
                                    value);
132
    }
133
    switch (offset >> 2) {
134
    case SYBORG_VIRTIO_GUEST_FEATURES:
135
        if (vdev->set_features)
136
            vdev->set_features(vdev, value);
137
        vdev->guest_features = value;
138
        break;
139
    case SYBORG_VIRTIO_QUEUE_BASE:
140
        if (value == 0)
141
            virtio_reset(vdev);
142
        else
143
            virtio_queue_set_addr(vdev, vdev->queue_sel, value);
144
        break;
145
    case SYBORG_VIRTIO_QUEUE_SEL:
146
        if (value < VIRTIO_PCI_QUEUE_MAX)
147
            vdev->queue_sel = value;
148
        break;
149
    case SYBORG_VIRTIO_QUEUE_NOTIFY:
150
        virtio_queue_notify(vdev, value);
151
        break;
152
    case SYBORG_VIRTIO_STATUS:
153
        virtio_set_status(vdev, value & 0xFF);
154
        if (vdev->status == 0)
155
            virtio_reset(vdev);
156
        break;
157
    case SYBORG_VIRTIO_INT_ENABLE:
158
        s->int_enable = value;
159
        virtio_update_irq(vdev);
160
        break;
161
    case SYBORG_VIRTIO_INT_STATUS:
162
        vdev->isr &= ~value;
163
        virtio_update_irq(vdev);
164
        break;
165
    default:
166
        BADF("Bad write offset 0x%x\n", (int)offset);
167
        break;
168
    }
169
}
170

    
171
static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
172
{
173
    SyborgVirtIOProxy *s = opaque;
174
    VirtIODevice *vdev = s->vdev;
175

    
176
    DPRINTF("readw 0x%x\n", (int)offset);
177
    if (offset >= SYBORG_VIRTIO_CONFIG) {
178
        return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
179
    }
180
    BADF("Bad halfword read offset 0x%x\n", (int)offset);
181
    return -1;
182
}
183

    
184
static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
185
                                 uint32_t value)
186
{
187
    SyborgVirtIOProxy *s = opaque;
188
    VirtIODevice *vdev = s->vdev;
189

    
190
    DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
191
    if (offset >= SYBORG_VIRTIO_CONFIG) {
192
        return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
193
                                    value);
194
    }
195
    BADF("Bad halfword write offset 0x%x\n", (int)offset);
196
}
197

    
198
static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
199
{
200
    SyborgVirtIOProxy *s = opaque;
201
    VirtIODevice *vdev = s->vdev;
202

    
203
    DPRINTF("readb 0x%x\n", (int)offset);
204
    if (offset >= SYBORG_VIRTIO_CONFIG) {
205
        return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
206
    }
207
    BADF("Bad byte read offset 0x%x\n", (int)offset);
208
    return -1;
209
}
210

    
211
static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
212
                                 uint32_t value)
213
{
214
    SyborgVirtIOProxy *s = opaque;
215
    VirtIODevice *vdev = s->vdev;
216

    
217
    DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
218
    if (offset >= SYBORG_VIRTIO_CONFIG) {
219
        return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
220
                                    value);
221
    }
222
    BADF("Bad byte write offset 0x%x\n", (int)offset);
223
}
224

    
225
static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
226
     syborg_virtio_readb,
227
     syborg_virtio_readw,
228
     syborg_virtio_readl
229
};
230

    
231
static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
232
     syborg_virtio_writeb,
233
     syborg_virtio_writew,
234
     syborg_virtio_writel
235
};
236

    
237
static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
238
{
239
    SyborgVirtIOProxy *proxy = opaque;
240
    int level;
241

    
242
    level = proxy->int_enable & proxy->vdev->isr;
243
    DPRINTF("IRQ %d\n", level);
244
    qemu_set_irq(proxy->irq, level != 0);
245
}
246

    
247
static unsigned syborg_virtio_get_features(void *opaque)
248
{
249
    SyborgVirtIOProxy *proxy = opaque;
250
    return proxy->host_features;
251
}
252

    
253
static VirtIOBindings syborg_virtio_bindings = {
254
    .notify = syborg_virtio_update_irq,
255
    .get_features = syborg_virtio_get_features,
256
};
257

    
258
static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
259
{
260
    int iomemtype;
261

    
262
    proxy->vdev = vdev;
263

    
264
    /* Don't support multiple vectors */
265
    proxy->vdev->nvectors = 0;
266
    sysbus_init_irq(&proxy->busdev, &proxy->irq);
267
    iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
268
                                       syborg_virtio_writefn, proxy);
269
    sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
270

    
271
    proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
272

    
273
    qemu_register_reset(virtio_reset, vdev);
274

    
275
    virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
276
    proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
277
    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
278
    return 0;
279
}
280

    
281
/* Device specific bindings.  */
282

    
283
static int syborg_virtio_net_init(SysBusDevice *dev)
284
{
285
    VirtIODevice *vdev;
286
    SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
287

    
288
    vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
289
    return syborg_virtio_init(proxy, vdev);
290
}
291

    
292
static SysBusDeviceInfo syborg_virtio_net_info = {
293
    .init = syborg_virtio_net_init,
294
    .qdev.name  = "syborg,virtio-net",
295
    .qdev.size  = sizeof(SyborgVirtIOProxy),
296
    .qdev.props = (Property[]) {
297
        DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
298
        DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
299
        DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
300
                           net.txtimer, TX_TIMER_INTERVAL),
301
        DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
302
                          net.txburst, TX_BURST),
303
        DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
304
        DEFINE_PROP_END_OF_LIST(),
305
    }
306
};
307

    
308
static void syborg_virtio_register_devices(void)
309
{
310
    sysbus_register_withprop(&syborg_virtio_net_info);
311
}
312

    
313
device_init(syborg_virtio_register_devices)