]> git.proxmox.com Git - qemu.git/blob - hw/syborg_virtio.c
ee08c49105f8ed6c33e02c7612f5eda501895236
[qemu.git] / hw / syborg_virtio.c
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 #include "sysemu.h"
30
31 //#define DEBUG_SYBORG_VIRTIO
32
33 #ifdef DEBUG_SYBORG_VIRTIO
34 #define DPRINTF(fmt, ...) \
35 do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
36 #define BADF(fmt, ...) \
37 do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__); \
38 exit(1);} while (0)
39 #else
40 #define DPRINTF(fmt, ...) do {} while(0)
41 #define BADF(fmt, ...) \
42 do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
43 #endif
44
45 enum {
46 SYBORG_VIRTIO_ID = 0,
47 SYBORG_VIRTIO_DEVTYPE = 1,
48 SYBORG_VIRTIO_HOST_FEATURES = 2,
49 SYBORG_VIRTIO_GUEST_FEATURES = 3,
50 SYBORG_VIRTIO_QUEUE_BASE = 4,
51 SYBORG_VIRTIO_QUEUE_NUM = 5,
52 SYBORG_VIRTIO_QUEUE_SEL = 6,
53 SYBORG_VIRTIO_QUEUE_NOTIFY = 7,
54 SYBORG_VIRTIO_STATUS = 8,
55 SYBORG_VIRTIO_INT_ENABLE = 9,
56 SYBORG_VIRTIO_INT_STATUS = 10
57 };
58
59 #define SYBORG_VIRTIO_CONFIG 0x100
60
61 /* Device independent interface. */
62
63 typedef struct {
64 SysBusDevice busdev;
65 VirtIODevice *vdev;
66 qemu_irq irq;
67 uint32_t int_enable;
68 uint32_t id;
69 NICConf nic;
70 uint32_t host_features;
71 virtio_net_conf net;
72 } SyborgVirtIOProxy;
73
74 static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
75 {
76 SyborgVirtIOProxy *s = opaque;
77 VirtIODevice *vdev = s->vdev;
78 uint32_t ret;
79
80 DPRINTF("readl 0x%x\n", (int)offset);
81 if (offset >= SYBORG_VIRTIO_CONFIG) {
82 return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
83 }
84 switch(offset >> 2) {
85 case SYBORG_VIRTIO_ID:
86 ret = SYBORG_ID_VIRTIO;
87 break;
88 case SYBORG_VIRTIO_DEVTYPE:
89 ret = s->id;
90 break;
91 case SYBORG_VIRTIO_HOST_FEATURES:
92 ret = s->host_features;
93 break;
94 case SYBORG_VIRTIO_GUEST_FEATURES:
95 ret = vdev->guest_features;
96 break;
97 case SYBORG_VIRTIO_QUEUE_BASE:
98 ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
99 break;
100 case SYBORG_VIRTIO_QUEUE_NUM:
101 ret = virtio_queue_get_num(vdev, vdev->queue_sel);
102 break;
103 case SYBORG_VIRTIO_QUEUE_SEL:
104 ret = vdev->queue_sel;
105 break;
106 case SYBORG_VIRTIO_STATUS:
107 ret = vdev->status;
108 break;
109 case SYBORG_VIRTIO_INT_ENABLE:
110 ret = s->int_enable;
111 break;
112 case SYBORG_VIRTIO_INT_STATUS:
113 ret = vdev->isr;
114 break;
115 default:
116 BADF("Bad read offset 0x%x\n", (int)offset);
117 return 0;
118 }
119 return ret;
120 }
121
122 static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
123 uint32_t value)
124 {
125 SyborgVirtIOProxy *s = opaque;
126 VirtIODevice *vdev = s->vdev;
127
128 DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
129 if (offset >= SYBORG_VIRTIO_CONFIG) {
130 return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
131 value);
132 }
133 switch (offset >> 2) {
134 case SYBORG_VIRTIO_GUEST_FEATURES:
135 if (vdev->set_features)
136 vdev->set_features(vdev, value);
137 vdev->guest_features = value;
138 break;
139 case SYBORG_VIRTIO_QUEUE_BASE:
140 if (value == 0)
141 virtio_reset(vdev);
142 else
143 virtio_queue_set_addr(vdev, vdev->queue_sel, value);
144 break;
145 case SYBORG_VIRTIO_QUEUE_SEL:
146 if (value < VIRTIO_PCI_QUEUE_MAX)
147 vdev->queue_sel = value;
148 break;
149 case SYBORG_VIRTIO_QUEUE_NOTIFY:
150 virtio_queue_notify(vdev, value);
151 break;
152 case SYBORG_VIRTIO_STATUS:
153 virtio_set_status(vdev, value & 0xFF);
154 if (vdev->status == 0)
155 virtio_reset(vdev);
156 break;
157 case SYBORG_VIRTIO_INT_ENABLE:
158 s->int_enable = value;
159 virtio_update_irq(vdev);
160 break;
161 case SYBORG_VIRTIO_INT_STATUS:
162 vdev->isr &= ~value;
163 virtio_update_irq(vdev);
164 break;
165 default:
166 BADF("Bad write offset 0x%x\n", (int)offset);
167 break;
168 }
169 }
170
171 static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
172 {
173 SyborgVirtIOProxy *s = opaque;
174 VirtIODevice *vdev = s->vdev;
175
176 DPRINTF("readw 0x%x\n", (int)offset);
177 if (offset >= SYBORG_VIRTIO_CONFIG) {
178 return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
179 }
180 BADF("Bad halfword read offset 0x%x\n", (int)offset);
181 return -1;
182 }
183
184 static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
185 uint32_t value)
186 {
187 SyborgVirtIOProxy *s = opaque;
188 VirtIODevice *vdev = s->vdev;
189
190 DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
191 if (offset >= SYBORG_VIRTIO_CONFIG) {
192 return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
193 value);
194 }
195 BADF("Bad halfword write offset 0x%x\n", (int)offset);
196 }
197
198 static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
199 {
200 SyborgVirtIOProxy *s = opaque;
201 VirtIODevice *vdev = s->vdev;
202
203 DPRINTF("readb 0x%x\n", (int)offset);
204 if (offset >= SYBORG_VIRTIO_CONFIG) {
205 return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
206 }
207 BADF("Bad byte read offset 0x%x\n", (int)offset);
208 return -1;
209 }
210
211 static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
212 uint32_t value)
213 {
214 SyborgVirtIOProxy *s = opaque;
215 VirtIODevice *vdev = s->vdev;
216
217 DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
218 if (offset >= SYBORG_VIRTIO_CONFIG) {
219 return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
220 value);
221 }
222 BADF("Bad byte write offset 0x%x\n", (int)offset);
223 }
224
225 static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
226 syborg_virtio_readb,
227 syborg_virtio_readw,
228 syborg_virtio_readl
229 };
230
231 static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
232 syborg_virtio_writeb,
233 syborg_virtio_writew,
234 syborg_virtio_writel
235 };
236
237 static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
238 {
239 SyborgVirtIOProxy *proxy = opaque;
240 int level;
241
242 level = proxy->int_enable & proxy->vdev->isr;
243 DPRINTF("IRQ %d\n", level);
244 qemu_set_irq(proxy->irq, level != 0);
245 }
246
247 static unsigned syborg_virtio_get_features(void *opaque)
248 {
249 SyborgVirtIOProxy *proxy = opaque;
250 return proxy->host_features;
251 }
252
253 static VirtIOBindings syborg_virtio_bindings = {
254 .notify = syborg_virtio_update_irq,
255 .get_features = syborg_virtio_get_features,
256 };
257
258 static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
259 {
260 int iomemtype;
261
262 proxy->vdev = vdev;
263
264 /* Don't support multiple vectors */
265 proxy->vdev->nvectors = 0;
266 sysbus_init_irq(&proxy->busdev, &proxy->irq);
267 iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
268 syborg_virtio_writefn, proxy,
269 DEVICE_NATIVE_ENDIAN);
270 sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
271
272 proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
273
274 qemu_register_reset(virtio_reset, vdev);
275
276 virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
277 proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
278 proxy->host_features = vdev->get_features(vdev, proxy->host_features);
279 return 0;
280 }
281
282 /* Device specific bindings. */
283
284 static int syborg_virtio_net_init(SysBusDevice *dev)
285 {
286 VirtIODevice *vdev;
287 SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
288
289 vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
290 return syborg_virtio_init(proxy, vdev);
291 }
292
293 static SysBusDeviceInfo syborg_virtio_net_info = {
294 .init = syborg_virtio_net_init,
295 .qdev.name = "syborg,virtio-net",
296 .qdev.size = sizeof(SyborgVirtIOProxy),
297 .qdev.props = (Property[]) {
298 DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
299 DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
300 DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
301 net.txtimer, TX_TIMER_INTERVAL),
302 DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
303 net.txburst, TX_BURST),
304 DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
305 DEFINE_PROP_END_OF_LIST(),
306 }
307 };
308
309 static void syborg_virtio_register_devices(void)
310 {
311 sysbus_register_withprop(&syborg_virtio_net_info);
312 }
313
314 device_init(syborg_virtio_register_devices)