2 * Virtio Syborg bindings
4 * Copyright (c) 2009 CodeSourcery
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
28 #include "virtio-net.h"
30 //#define DEBUG_SYBORG_VIRTIO
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__); \
39 #define DPRINTF(fmt, ...) do {} while(0)
40 #define BADF(fmt, ...) \
41 do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (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
58 #define SYBORG_VIRTIO_CONFIG 0x100
60 /* Device independent interface. */
69 uint32_t host_features
;
73 static uint32_t syborg_virtio_readl(void *opaque
, target_phys_addr_t offset
)
75 SyborgVirtIOProxy
*s
= opaque
;
76 VirtIODevice
*vdev
= s
->vdev
;
79 DPRINTF("readl 0x%x\n", (int)offset
);
80 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
81 return virtio_config_readl(vdev
, offset
- SYBORG_VIRTIO_CONFIG
);
84 case SYBORG_VIRTIO_ID
:
85 ret
= SYBORG_ID_VIRTIO
;
87 case SYBORG_VIRTIO_DEVTYPE
:
90 case SYBORG_VIRTIO_HOST_FEATURES
:
91 ret
= s
->host_features
;
93 case SYBORG_VIRTIO_GUEST_FEATURES
:
94 ret
= vdev
->guest_features
;
96 case SYBORG_VIRTIO_QUEUE_BASE
:
97 ret
= virtio_queue_get_addr(vdev
, vdev
->queue_sel
);
99 case SYBORG_VIRTIO_QUEUE_NUM
:
100 ret
= virtio_queue_get_num(vdev
, vdev
->queue_sel
);
102 case SYBORG_VIRTIO_QUEUE_SEL
:
103 ret
= vdev
->queue_sel
;
105 case SYBORG_VIRTIO_STATUS
:
108 case SYBORG_VIRTIO_INT_ENABLE
:
111 case SYBORG_VIRTIO_INT_STATUS
:
115 BADF("Bad read offset 0x%x\n", (int)offset
);
121 static void syborg_virtio_writel(void *opaque
, target_phys_addr_t offset
,
124 SyborgVirtIOProxy
*s
= opaque
;
125 VirtIODevice
*vdev
= s
->vdev
;
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
,
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
;
138 case SYBORG_VIRTIO_QUEUE_BASE
:
142 virtio_queue_set_addr(vdev
, vdev
->queue_sel
, value
);
144 case SYBORG_VIRTIO_QUEUE_SEL
:
145 if (value
< VIRTIO_PCI_QUEUE_MAX
)
146 vdev
->queue_sel
= value
;
148 case SYBORG_VIRTIO_QUEUE_NOTIFY
:
149 if (value
< VIRTIO_PCI_QUEUE_MAX
) {
150 virtio_queue_notify(vdev
, value
);
153 case SYBORG_VIRTIO_STATUS
:
154 virtio_set_status(vdev
, value
& 0xFF);
155 if (vdev
->status
== 0)
158 case SYBORG_VIRTIO_INT_ENABLE
:
159 s
->int_enable
= value
;
160 virtio_update_irq(vdev
);
162 case SYBORG_VIRTIO_INT_STATUS
:
164 virtio_update_irq(vdev
);
167 BADF("Bad write offset 0x%x\n", (int)offset
);
172 static uint32_t syborg_virtio_readw(void *opaque
, target_phys_addr_t offset
)
174 SyborgVirtIOProxy
*s
= opaque
;
175 VirtIODevice
*vdev
= s
->vdev
;
177 DPRINTF("readw 0x%x\n", (int)offset
);
178 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
179 return virtio_config_readw(vdev
, offset
- SYBORG_VIRTIO_CONFIG
);
181 BADF("Bad halfword read offset 0x%x\n", (int)offset
);
185 static void syborg_virtio_writew(void *opaque
, target_phys_addr_t offset
,
188 SyborgVirtIOProxy
*s
= opaque
;
189 VirtIODevice
*vdev
= s
->vdev
;
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
,
196 BADF("Bad halfword write offset 0x%x\n", (int)offset
);
199 static uint32_t syborg_virtio_readb(void *opaque
, target_phys_addr_t offset
)
201 SyborgVirtIOProxy
*s
= opaque
;
202 VirtIODevice
*vdev
= s
->vdev
;
204 DPRINTF("readb 0x%x\n", (int)offset
);
205 if (offset
>= SYBORG_VIRTIO_CONFIG
) {
206 return virtio_config_readb(vdev
, offset
- SYBORG_VIRTIO_CONFIG
);
208 BADF("Bad byte read offset 0x%x\n", (int)offset
);
212 static void syborg_virtio_writeb(void *opaque
, target_phys_addr_t offset
,
215 SyborgVirtIOProxy
*s
= opaque
;
216 VirtIODevice
*vdev
= s
->vdev
;
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
,
223 BADF("Bad byte write offset 0x%x\n", (int)offset
);
226 static CPUReadMemoryFunc
* const syborg_virtio_readfn
[] = {
232 static CPUWriteMemoryFunc
* const syborg_virtio_writefn
[] = {
233 syborg_virtio_writeb
,
234 syborg_virtio_writew
,
238 static void syborg_virtio_update_irq(void *opaque
, uint16_t vector
)
240 SyborgVirtIOProxy
*proxy
= opaque
;
243 level
= proxy
->int_enable
& proxy
->vdev
->isr
;
244 DPRINTF("IRQ %d\n", level
);
245 qemu_set_irq(proxy
->irq
, level
!= 0);
248 static unsigned syborg_virtio_get_features(void *opaque
)
250 SyborgVirtIOProxy
*proxy
= opaque
;
251 return proxy
->host_features
;
254 static VirtIOBindings syborg_virtio_bindings
= {
255 .notify
= syborg_virtio_update_irq
,
256 .get_features
= syborg_virtio_get_features
,
259 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 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
);
273 proxy
->id
= ((uint32_t)0x1af4 << 16) | vdev
->device_id
;
275 qemu_register_reset(virtio_reset
, vdev
);
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
);
283 /* Device specific bindings. */
285 static int syborg_virtio_net_init(SysBusDevice
*dev
)
288 SyborgVirtIOProxy
*proxy
= FROM_SYSBUS(SyborgVirtIOProxy
, dev
);
290 vdev
= virtio_net_init(&dev
->qdev
, &proxy
->nic
, &proxy
->net
);
291 return syborg_virtio_init(proxy
, vdev
);
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(),
310 static void syborg_virtio_register_devices(void)
312 sysbus_register_withprop(&syborg_virtio_net_info
);
315 device_init(syborg_virtio_register_devices
)