2 * Virtio Syborg bindings
4 * Copyright (c) 2009 CodeSourcery
5 * Copyright (c) 2010, 2013 Stefan Weil
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #include "qemu/osdep.h"
28 #include "hw/sysbus.h"
30 #include "virtio-net.h"
32 //#define DEBUG_SYBORG_VIRTIO
34 #ifdef DEBUG_SYBORG_VIRTIO
35 #define DPRINTF(fmt, ...) \
36 do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
37 #define BADF(fmt, ...) \
38 do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__); \
41 #define DPRINTF(fmt, ...) do {} while(0)
42 #define BADF(fmt, ...) \
43 do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
48 SYBORG_VIRTIO_DEVTYPE
= 1,
49 SYBORG_VIRTIO_HOST_FEATURES
= 2,
50 SYBORG_VIRTIO_GUEST_FEATURES
= 3,
51 SYBORG_VIRTIO_QUEUE_BASE
= 4,
52 SYBORG_VIRTIO_QUEUE_NUM
= 5,
53 SYBORG_VIRTIO_QUEUE_SEL
= 6,
54 SYBORG_VIRTIO_QUEUE_NOTIFY
= 7,
55 SYBORG_VIRTIO_STATUS
= 8,
56 SYBORG_VIRTIO_INT_ENABLE
= 9,
57 SYBORG_VIRTIO_INT_STATUS
= 10
60 #define SYBORG_VIRTIO_CONFIG 0x100
62 /* Device independent interface. */
72 uint32_t host_features
;
76 static SyborgVirtIOProxy
*to_virtio_syborg_device(DeviceState
*d
)
78 return container_of(d
, SyborgVirtIOProxy
, busdev
.qdev
);
81 static uint32_t syborg_virtio_readl(void *opaque
, hwaddr offset
)
83 SyborgVirtIOProxy
*s
= opaque
;
84 VirtIODevice
*vdev
= s
->vdev
;
87 DPRINTF("readl 0x%x\n", (int)offset
);
88 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
89 return virtio_config_readl(vdev
, offset
- SYBORG_VIRTIO_CONFIG
);
92 case SYBORG_VIRTIO_ID
:
93 ret
= SYBORG_ID_VIRTIO
;
95 case SYBORG_VIRTIO_DEVTYPE
:
98 case SYBORG_VIRTIO_HOST_FEATURES
:
99 ret
= s
->host_features
;
101 case SYBORG_VIRTIO_GUEST_FEATURES
:
102 ret
= vdev
->guest_features
;
104 case SYBORG_VIRTIO_QUEUE_BASE
:
105 ret
= virtio_queue_get_addr(vdev
, vdev
->queue_sel
);
107 case SYBORG_VIRTIO_QUEUE_NUM
:
108 ret
= virtio_queue_get_num(vdev
, vdev
->queue_sel
);
110 case SYBORG_VIRTIO_QUEUE_SEL
:
111 ret
= vdev
->queue_sel
;
113 case SYBORG_VIRTIO_STATUS
:
116 case SYBORG_VIRTIO_INT_ENABLE
:
119 case SYBORG_VIRTIO_INT_STATUS
:
123 BADF("Bad read offset 0x%x\n", (int)offset
);
129 static void syborg_virtio_writel(void *opaque
, hwaddr offset
,
132 SyborgVirtIOProxy
*s
= opaque
;
133 VirtIODevice
*vdev
= s
->vdev
;
135 DPRINTF("writel 0x%x = 0x%x\n", (int)offset
, value
);
136 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
137 return virtio_config_writel(vdev
, offset
- SYBORG_VIRTIO_CONFIG
,
140 switch (offset
>> 2) {
141 case SYBORG_VIRTIO_GUEST_FEATURES
:
142 virtio_set_features(vdev
, value
);
144 case SYBORG_VIRTIO_QUEUE_BASE
:
148 virtio_queue_set_addr(vdev
, vdev
->queue_sel
, value
);
150 case SYBORG_VIRTIO_QUEUE_SEL
:
151 if (value
< VIRTIO_PCI_QUEUE_MAX
)
152 vdev
->queue_sel
= value
;
154 case SYBORG_VIRTIO_QUEUE_NOTIFY
:
155 if (value
< VIRTIO_PCI_QUEUE_MAX
) {
156 virtio_queue_notify(vdev
, value
);
159 case SYBORG_VIRTIO_STATUS
:
160 virtio_set_status(vdev
, value
& 0xFF);
161 if (vdev
->status
== 0)
164 case SYBORG_VIRTIO_INT_ENABLE
:
165 s
->int_enable
= value
;
166 virtio_update_irq(vdev
);
168 case SYBORG_VIRTIO_INT_STATUS
:
170 virtio_update_irq(vdev
);
173 BADF("Bad write offset 0x%x\n", (int)offset
);
178 static uint32_t syborg_virtio_readw(void *opaque
, hwaddr offset
)
180 SyborgVirtIOProxy
*s
= opaque
;
181 VirtIODevice
*vdev
= s
->vdev
;
183 DPRINTF("readw 0x%x\n", (int)offset
);
184 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
185 return virtio_config_readw(vdev
, offset
- SYBORG_VIRTIO_CONFIG
);
187 BADF("Bad halfword read offset 0x%x\n", (int)offset
);
191 static void syborg_virtio_writew(void *opaque
, hwaddr offset
,
194 SyborgVirtIOProxy
*s
= opaque
;
195 VirtIODevice
*vdev
= s
->vdev
;
197 DPRINTF("writew 0x%x = 0x%x\n", (int)offset
, value
);
198 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
199 return virtio_config_writew(vdev
, offset
- SYBORG_VIRTIO_CONFIG
,
202 BADF("Bad halfword write offset 0x%x\n", (int)offset
);
205 static uint32_t syborg_virtio_readb(void *opaque
, hwaddr offset
)
207 SyborgVirtIOProxy
*s
= opaque
;
208 VirtIODevice
*vdev
= s
->vdev
;
210 DPRINTF("readb 0x%x\n", (int)offset
);
211 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
212 return virtio_config_readb(vdev
, offset
- SYBORG_VIRTIO_CONFIG
);
214 BADF("Bad byte read offset 0x%x\n", (int)offset
);
218 static void syborg_virtio_writeb(void *opaque
, hwaddr offset
,
221 SyborgVirtIOProxy
*s
= opaque
;
222 VirtIODevice
*vdev
= s
->vdev
;
224 DPRINTF("writeb 0x%x = 0x%x\n", (int)offset
, value
);
225 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
226 return virtio_config_writeb(vdev
, offset
- SYBORG_VIRTIO_CONFIG
,
229 BADF("Bad byte write offset 0x%x\n", (int)offset
);
232 static const MemoryRegionOps syborg_virtio_ops
= {
234 .read
= { syborg_virtio_readb
, syborg_virtio_readw
, syborg_virtio_readl
},
235 .write
= { syborg_virtio_writeb
, syborg_virtio_writew
, syborg_virtio_writel
},
237 .endianness
= DEVICE_NATIVE_ENDIAN
,
240 static void syborg_virtio_update_irq(DeviceState
*d
, uint16_t vector
)
242 SyborgVirtIOProxy
*proxy
= to_virtio_syborg_device(d
);
245 level
= proxy
->int_enable
& proxy
->vdev
->isr
;
246 DPRINTF("IRQ %d\n", level
);
247 qemu_set_irq(proxy
->irq
, level
!= 0);
250 static unsigned syborg_virtio_get_features(DeviceState
*d
)
252 SyborgVirtIOProxy
*proxy
= to_virtio_syborg_device(d
);
253 return proxy
->host_features
;
256 static VirtIOBindings syborg_virtio_bindings
= {
257 .notify
= syborg_virtio_update_irq
,
258 .get_features
= syborg_virtio_get_features
,
261 static int syborg_virtio_init(SyborgVirtIOProxy
*proxy
, VirtIODevice
*vdev
)
265 /* Don't support multiple vectors */
266 proxy
->vdev
->nvectors
= 0;
267 sysbus_init_irq(&proxy
->busdev
, &proxy
->irq
);
268 memory_region_init_io(&proxy
->iomem
, &syborg_virtio_ops
, proxy
,
270 sysbus_init_mmio(&proxy
->busdev
, &proxy
->iomem
);
272 proxy
->id
= ((uint32_t)0x1af4 << 16) | vdev
->device_id
;
274 qemu_register_reset(virtio_reset
, vdev
);
276 virtio_bind_device(vdev
, &syborg_virtio_bindings
, DEVICE(proxy
));
277 proxy
->host_features
|= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY
);
278 proxy
->host_features
= vdev
->get_features(vdev
, proxy
->host_features
);
282 /* Device specific bindings. */
284 static int syborg_virtio_net_init(SysBusDevice
*sbd
)
287 DeviceState
*dev
= DEVICE(sbd
);
288 SyborgVirtIOProxy
*proxy
= SYBORG_VIRTIOPROXY(dev
);
290 vdev
= virtio_net_init(&dev
->qdev
, &proxy
->nic
, &proxy
->net
,
291 proxy
->host_features
);
293 return syborg_virtio_init(proxy
, vdev
);
296 static Property syborg_virtio_net_properties
[] = {
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()
307 static void syborg_virtio_net_class_init(ObjectClass
*klass
, void *data
)
309 DeviceClass
*dc
= DEVICE_CLASS(klass
);
310 SysBusDeviceClass
*k
= SYS_BUS_DEVICE_CLASS(klass
);
311 dc
->props
= syborg_virtio_net_properties
;
312 k
->init
= syborg_virtio_net_init
;
315 static const TypeInfo syborg_virtio_net_info
= {
316 .name
= "syborg,virtio-net",
317 .parent
= TYPE_SYS_BUS_DEVICE
,
318 .instance_size
= sizeof(SyborgVirtIOProxy
),
319 .class_init
= syborg_virtio_net_class_init
322 static void syborg_virtio_register_types(void)
324 type_register_static(&syborg_virtio_net_info
);
327 type_init(syborg_virtio_register_types
)