Statistics
| Branch: | Revision:

root / hw / syborg_virtio.c @ 462a8bc6

History | View | Annotate | Download (9.5 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

    
30
//#define DEBUG_SYBORG_VIRTIO
31

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

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

    
58
#define SYBORG_VIRTIO_CONFIG 0x100
59

    
60
/* Device independent interface.  */
61

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
263
    proxy->vdev = vdev;
264

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

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

    
275
    qemu_register_reset(virtio_reset, vdev);
276

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

    
283
/* Device specific bindings.  */
284

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

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

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

    
310
static void syborg_virtio_register_devices(void)
311
{
312
    sysbus_register_withprop(&syborg_virtio_net_info);
313
}
314

    
315
device_init(syborg_virtio_register_devices)