]> git.proxmox.com Git - mirror_qemu.git/blame - hw/syborg_virtio.c
qdev: add return value to init() callbacks.
[mirror_qemu.git] / hw / syborg_virtio.c
CommitLineData
340d96e7
PB
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, ...) \
34do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
35#define BADF(fmt, ...) \
36do { 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, ...) \
41do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
42#endif
43
44enum {
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
62typedef struct {
63 SysBusDevice busdev;
64 VirtIODevice *vdev;
65 qemu_irq irq;
66 uint32_t int_enable;
67 uint32_t id;
68} SyborgVirtIOProxy;
69
70static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
71{
72 SyborgVirtIOProxy *s = opaque;
73 VirtIODevice *vdev = s->vdev;
74 uint32_t ret;
75
76 DPRINTF("readl 0x%x\n", (int)offset);
77 if (offset >= SYBORG_VIRTIO_CONFIG) {
78 return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
79 }
80 switch(offset >> 2) {
81 case SYBORG_VIRTIO_ID:
82 ret = SYBORG_ID_VIRTIO;
83 break;
84 case SYBORG_VIRTIO_DEVTYPE:
85 ret = s->id;
86 break;
87 case SYBORG_VIRTIO_HOST_FEATURES:
88 ret = vdev->get_features(vdev);
89 ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
90 break;
91 case SYBORG_VIRTIO_GUEST_FEATURES:
92 ret = vdev->features;
93 break;
94 case SYBORG_VIRTIO_QUEUE_BASE:
95 ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
96 break;
97 case SYBORG_VIRTIO_QUEUE_NUM:
98 ret = virtio_queue_get_num(vdev, vdev->queue_sel);
99 break;
100 case SYBORG_VIRTIO_QUEUE_SEL:
101 ret = vdev->queue_sel;
102 break;
103 case SYBORG_VIRTIO_STATUS:
104 ret = vdev->status;
105 break;
106 case SYBORG_VIRTIO_INT_ENABLE:
107 ret = s->int_enable;
108 break;
109 case SYBORG_VIRTIO_INT_STATUS:
110 ret = vdev->isr;
111 break;
112 default:
113 BADF("Bad read offset 0x%x\n", (int)offset);
114 return 0;
115 }
116 return ret;
117}
118
119static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
120 uint32_t value)
121{
122 SyborgVirtIOProxy *s = opaque;
123 VirtIODevice *vdev = s->vdev;
124
125 DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
126 if (offset >= SYBORG_VIRTIO_CONFIG) {
127 return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
128 value);
129 }
130 switch (offset >> 2) {
131 case SYBORG_VIRTIO_GUEST_FEATURES:
132 if (vdev->set_features)
133 vdev->set_features(vdev, value);
134 vdev->features = value;
135 break;
136 case SYBORG_VIRTIO_QUEUE_BASE:
7055e687
MT
137 if (value == 0)
138 virtio_reset(vdev);
139 else
140 virtio_queue_set_addr(vdev, vdev->queue_sel, value);
340d96e7
PB
141 break;
142 case SYBORG_VIRTIO_QUEUE_SEL:
143 if (value < VIRTIO_PCI_QUEUE_MAX)
144 vdev->queue_sel = value;
145 break;
146 case SYBORG_VIRTIO_QUEUE_NOTIFY:
147 virtio_queue_notify(vdev, value);
148 break;
149 case SYBORG_VIRTIO_STATUS:
150 vdev->status = value & 0xFF;
151 if (vdev->status == 0)
152 virtio_reset(vdev);
153 break;
154 case SYBORG_VIRTIO_INT_ENABLE:
155 s->int_enable = value;
156 virtio_update_irq(vdev);
157 break;
158 case SYBORG_VIRTIO_INT_STATUS:
159 vdev->isr &= ~value;
160 virtio_update_irq(vdev);
161 break;
162 default:
163 BADF("Bad write offset 0x%x\n", (int)offset);
164 break;
165 }
166}
167
168static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
169{
170 SyborgVirtIOProxy *s = opaque;
171 VirtIODevice *vdev = s->vdev;
172
173 DPRINTF("readw 0x%x\n", (int)offset);
174 if (offset >= SYBORG_VIRTIO_CONFIG) {
175 return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
176 }
177 BADF("Bad halfword read offset 0x%x\n", (int)offset);
178 return -1;
179}
180
181static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
182 uint32_t value)
183{
184 SyborgVirtIOProxy *s = opaque;
185 VirtIODevice *vdev = s->vdev;
186
187 DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
188 if (offset >= SYBORG_VIRTIO_CONFIG) {
189 return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
190 value);
191 }
192 BADF("Bad halfword write offset 0x%x\n", (int)offset);
193}
194
195static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
196{
197 SyborgVirtIOProxy *s = opaque;
198 VirtIODevice *vdev = s->vdev;
199
200 DPRINTF("readb 0x%x\n", (int)offset);
201 if (offset >= SYBORG_VIRTIO_CONFIG) {
202 return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
203 }
204 BADF("Bad byte read offset 0x%x\n", (int)offset);
205 return -1;
206}
207
208static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
209 uint32_t value)
210{
211 SyborgVirtIOProxy *s = opaque;
212 VirtIODevice *vdev = s->vdev;
213
214 DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
215 if (offset >= SYBORG_VIRTIO_CONFIG) {
216 return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
217 value);
218 }
219 BADF("Bad byte write offset 0x%x\n", (int)offset);
220}
221
d60efc6b 222static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
340d96e7
PB
223 syborg_virtio_readb,
224 syborg_virtio_readw,
225 syborg_virtio_readl
226};
227
d60efc6b 228static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
340d96e7
PB
229 syborg_virtio_writeb,
230 syborg_virtio_writew,
231 syborg_virtio_writel
232};
233
7055e687 234static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
340d96e7
PB
235{
236 SyborgVirtIOProxy *proxy = opaque;
237 int level;
238
239 level = proxy->int_enable & proxy->vdev->isr;
240 DPRINTF("IRQ %d\n", level);
241 qemu_set_irq(proxy->irq, level != 0);
242}
243
244static VirtIOBindings syborg_virtio_bindings = {
7055e687 245 .notify = syborg_virtio_update_irq
340d96e7
PB
246};
247
81a322d4 248static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
340d96e7
PB
249{
250 int iomemtype;
251
252 proxy->vdev = vdev;
253
7055e687
MT
254 /* Don't support multiple vectors */
255 proxy->vdev->nvectors = 0;
340d96e7 256 sysbus_init_irq(&proxy->busdev, &proxy->irq);
1eed09cb 257 iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
340d96e7
PB
258 syborg_virtio_writefn, proxy);
259 sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
260
261 proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
262
a08d4367 263 qemu_register_reset(virtio_reset, vdev);
7055e687 264
340d96e7 265 virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
81a322d4 266 return 0;
340d96e7
PB
267}
268
269/* Device specific bindings. */
270
81a322d4 271static int syborg_virtio_net_init(SysBusDevice *dev)
340d96e7
PB
272{
273 VirtIODevice *vdev;
274 SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
275
276 vdev = virtio_net_init(&dev->qdev);
81a322d4 277 return syborg_virtio_init(proxy, vdev);
340d96e7
PB
278}
279
280static void syborg_virtio_register_devices(void)
281{
282 sysbus_register_dev("syborg,virtio-net", sizeof(SyborgVirtIOProxy),
283 syborg_virtio_net_init);
284}
285
286device_init(syborg_virtio_register_devices)