]> Git Repo - qemu.git/blob - hw/syborg_virtio.c
ide: port pci ide to vmstate
[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 |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
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 VirtIOBindings syborg_virtio_bindings = {
246     .notify = syborg_virtio_update_irq
247 };
248
249 static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
250 {
251     int iomemtype;
252
253     proxy->vdev = vdev;
254
255     /* Don't support multiple vectors */
256     proxy->vdev->nvectors = 0;
257     sysbus_init_irq(&proxy->busdev, &proxy->irq);
258     iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
259                                        syborg_virtio_writefn, proxy);
260     sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
261
262     proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
263
264     qemu_register_reset(virtio_reset, vdev);
265
266     virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
267     return 0;
268 }
269
270 /* Device specific bindings.  */
271
272 static int syborg_virtio_net_init(SysBusDevice *dev)
273 {
274     VirtIODevice *vdev;
275     SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
276
277     vdev = virtio_net_init(&dev->qdev, &proxy->nic);
278     return syborg_virtio_init(proxy, vdev);
279 }
280
281 static SysBusDeviceInfo syborg_virtio_net_info = {
282     .init = syborg_virtio_net_init,
283     .qdev.name  = "syborg,virtio-net",
284     .qdev.size  = sizeof(SyborgVirtIOProxy),
285     .qdev.props = (Property[]) {
286         DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
287         DEFINE_PROP_END_OF_LIST(),
288     }
289 };
290
291 static void syborg_virtio_register_devices(void)
292 {
293     sysbus_register_withprop(&syborg_virtio_net_info);
294 }
295
296 device_init(syborg_virtio_register_devices)
This page took 0.043749 seconds and 4 git commands to generate.