]> Git Repo - qemu.git/blob - hw/syborg_virtio.c
qxl: bump pci rev
[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
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     uint32_t host_features;
70     virtio_net_conf net;
71 } SyborgVirtIOProxy;
72
73 static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
74 {
75     SyborgVirtIOProxy *s = opaque;
76     VirtIODevice *vdev = s->vdev;
77     uint32_t ret;
78
79     DPRINTF("readl 0x%x\n", (int)offset);
80     if (offset >= SYBORG_VIRTIO_CONFIG) {
81         return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
82     }
83     switch(offset >> 2) {
84     case SYBORG_VIRTIO_ID:
85         ret = SYBORG_ID_VIRTIO;
86         break;
87     case SYBORG_VIRTIO_DEVTYPE:
88         ret = s->id;
89         break;
90     case SYBORG_VIRTIO_HOST_FEATURES:
91         ret = s->host_features;
92         break;
93     case SYBORG_VIRTIO_GUEST_FEATURES:
94         ret = vdev->guest_features;
95         break;
96     case SYBORG_VIRTIO_QUEUE_BASE:
97         ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
98         break;
99     case SYBORG_VIRTIO_QUEUE_NUM:
100         ret = virtio_queue_get_num(vdev, vdev->queue_sel);
101         break;
102     case SYBORG_VIRTIO_QUEUE_SEL:
103         ret = vdev->queue_sel;
104         break;
105     case SYBORG_VIRTIO_STATUS:
106         ret = vdev->status;
107         break;
108     case SYBORG_VIRTIO_INT_ENABLE:
109         ret = s->int_enable;
110         break;
111     case SYBORG_VIRTIO_INT_STATUS:
112         ret = vdev->isr;
113         break;
114     default:
115         BADF("Bad read offset 0x%x\n", (int)offset);
116         return 0;
117     }
118     return ret;
119 }
120
121 static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
122                                  uint32_t value)
123 {
124     SyborgVirtIOProxy *s = opaque;
125     VirtIODevice *vdev = s->vdev;
126
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,
130                                     value);
131     }
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;
137         break;
138     case SYBORG_VIRTIO_QUEUE_BASE:
139         if (value == 0)
140             virtio_reset(vdev);
141         else
142             virtio_queue_set_addr(vdev, vdev->queue_sel, value);
143         break;
144     case SYBORG_VIRTIO_QUEUE_SEL:
145         if (value < VIRTIO_PCI_QUEUE_MAX)
146             vdev->queue_sel = value;
147         break;
148     case SYBORG_VIRTIO_QUEUE_NOTIFY:
149         if (value < VIRTIO_PCI_QUEUE_MAX) {
150             virtio_queue_notify(vdev, value);
151         }
152         break;
153     case SYBORG_VIRTIO_STATUS:
154         virtio_set_status(vdev, value & 0xFF);
155         if (vdev->status == 0)
156             virtio_reset(vdev);
157         break;
158     case SYBORG_VIRTIO_INT_ENABLE:
159         s->int_enable = value;
160         virtio_update_irq(vdev);
161         break;
162     case SYBORG_VIRTIO_INT_STATUS:
163         vdev->isr &= ~value;
164         virtio_update_irq(vdev);
165         break;
166     default:
167         BADF("Bad write offset 0x%x\n", (int)offset);
168         break;
169     }
170 }
171
172 static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
173 {
174     SyborgVirtIOProxy *s = opaque;
175     VirtIODevice *vdev = s->vdev;
176
177     DPRINTF("readw 0x%x\n", (int)offset);
178     if (offset >= SYBORG_VIRTIO_CONFIG) {
179         return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
180     }
181     BADF("Bad halfword read offset 0x%x\n", (int)offset);
182     return -1;
183 }
184
185 static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
186                                  uint32_t value)
187 {
188     SyborgVirtIOProxy *s = opaque;
189     VirtIODevice *vdev = s->vdev;
190
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,
194                                     value);
195     }
196     BADF("Bad halfword write offset 0x%x\n", (int)offset);
197 }
198
199 static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
200 {
201     SyborgVirtIOProxy *s = opaque;
202     VirtIODevice *vdev = s->vdev;
203
204     DPRINTF("readb 0x%x\n", (int)offset);
205     if (offset >= SYBORG_VIRTIO_CONFIG) {
206         return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
207     }
208     BADF("Bad byte read offset 0x%x\n", (int)offset);
209     return -1;
210 }
211
212 static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
213                                  uint32_t value)
214 {
215     SyborgVirtIOProxy *s = opaque;
216     VirtIODevice *vdev = s->vdev;
217
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,
221                                     value);
222     }
223     BADF("Bad byte write offset 0x%x\n", (int)offset);
224 }
225
226 static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
227      syborg_virtio_readb,
228      syborg_virtio_readw,
229      syborg_virtio_readl
230 };
231
232 static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
233      syborg_virtio_writeb,
234      syborg_virtio_writew,
235      syborg_virtio_writel
236 };
237
238 static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
239 {
240     SyborgVirtIOProxy *proxy = opaque;
241     int level;
242
243     level = proxy->int_enable & proxy->vdev->isr;
244     DPRINTF("IRQ %d\n", level);
245     qemu_set_irq(proxy->irq, level != 0);
246 }
247
248 static unsigned syborg_virtio_get_features(void *opaque)
249 {
250     SyborgVirtIOProxy *proxy = opaque;
251     return proxy->host_features;
252 }
253
254 static VirtIOBindings syborg_virtio_bindings = {
255     .notify = syborg_virtio_update_irq,
256     .get_features = syborg_virtio_get_features,
257 };
258
259 static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
260 {
261     int iomemtype;
262
263     proxy->vdev = vdev;
264
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);
272
273     proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
274
275     qemu_register_reset(virtio_reset, vdev);
276
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);
280     return 0;
281 }
282
283 /* Device specific bindings.  */
284
285 static int syborg_virtio_net_init(SysBusDevice *dev)
286 {
287     VirtIODevice *vdev;
288     SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
289
290     vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
291     return syborg_virtio_init(proxy, vdev);
292 }
293
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(),
307     }
308 };
309
310 static void syborg_virtio_register_devices(void)
311 {
312     sysbus_register_withprop(&syborg_virtio_net_info);
313 }
314
315 device_init(syborg_virtio_register_devices)
This page took 0.041865 seconds and 4 git commands to generate.