Statistics
| Branch: | Revision:

root / hw / syborg_virtio.c @ 704a76fc

History | View | Annotate | Download (8.9 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 "sysemu.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
} SyborgVirtIOProxy;
70

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
245
static unsigned syborg_virtio_get_features(void *opaque)
246
{
247
    unsigned ret = 0;
248
    ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
249
    return ret;
250
}
251

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

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

    
261
    proxy->vdev = vdev;
262

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

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

    
272
    qemu_register_reset(virtio_reset, vdev);
273

    
274
    virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
275
    return 0;
276
}
277

    
278
/* Device specific bindings.  */
279

    
280
static int syborg_virtio_net_init(SysBusDevice *dev)
281
{
282
    VirtIODevice *vdev;
283
    SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
284

    
285
    vdev = virtio_net_init(&dev->qdev, &proxy->nic);
286
    return syborg_virtio_init(proxy, vdev);
287
}
288

    
289
static SysBusDeviceInfo syborg_virtio_net_info = {
290
    .init = syborg_virtio_net_init,
291
    .qdev.name  = "syborg,virtio-net",
292
    .qdev.size  = sizeof(SyborgVirtIOProxy),
293
    .qdev.props = (Property[]) {
294
        DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
295
        DEFINE_PROP_END_OF_LIST(),
296
    }
297
};
298

    
299
static void syborg_virtio_register_devices(void)
300
{
301
    sysbus_register_withprop(&syborg_virtio_net_info);
302
}
303

    
304
device_init(syborg_virtio_register_devices)