]> git.proxmox.com Git - qemu.git/blob - hw/syborg_virtio.c
list MST as pci layer maintainer
[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 "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->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->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)