root / hw / virtio-pci.c @ 1ad2134f
History | View | Annotate | Download (10.3 kB)
1 |
/*
|
---|---|
2 |
* Virtio PCI Bindings
|
3 |
*
|
4 |
* Copyright IBM, Corp. 2007
|
5 |
* Copyright (c) 2009 CodeSourcery
|
6 |
*
|
7 |
* Authors:
|
8 |
* Anthony Liguori <aliguori@us.ibm.com>
|
9 |
* Paul Brook <paul@codesourcery.com>
|
10 |
*
|
11 |
* This work is licensed under the terms of the GNU GPL, version 2. See
|
12 |
* the COPYING file in the top-level directory.
|
13 |
*
|
14 |
*/
|
15 |
|
16 |
#include <inttypes.h> |
17 |
|
18 |
#include "virtio.h" |
19 |
#include "pci.h" |
20 |
//#include "sysemu.h"
|
21 |
|
22 |
/* from Linux's linux/virtio_pci.h */
|
23 |
|
24 |
/* A 32-bit r/o bitmask of the features supported by the host */
|
25 |
#define VIRTIO_PCI_HOST_FEATURES 0 |
26 |
|
27 |
/* A 32-bit r/w bitmask of features activated by the guest */
|
28 |
#define VIRTIO_PCI_GUEST_FEATURES 4 |
29 |
|
30 |
/* A 32-bit r/w PFN for the currently selected queue */
|
31 |
#define VIRTIO_PCI_QUEUE_PFN 8 |
32 |
|
33 |
/* A 16-bit r/o queue size for the currently selected queue */
|
34 |
#define VIRTIO_PCI_QUEUE_NUM 12 |
35 |
|
36 |
/* A 16-bit r/w queue selector */
|
37 |
#define VIRTIO_PCI_QUEUE_SEL 14 |
38 |
|
39 |
/* A 16-bit r/w queue notifier */
|
40 |
#define VIRTIO_PCI_QUEUE_NOTIFY 16 |
41 |
|
42 |
/* An 8-bit device status register. */
|
43 |
#define VIRTIO_PCI_STATUS 18 |
44 |
|
45 |
/* An 8-bit r/o interrupt status register. Reading the value will return the
|
46 |
* current contents of the ISR and will also clear it. This is effectively
|
47 |
* a read-and-acknowledge. */
|
48 |
#define VIRTIO_PCI_ISR 19 |
49 |
|
50 |
#define VIRTIO_PCI_CONFIG 20 |
51 |
|
52 |
/* Virtio ABI version, if we increment this, we break the guest driver. */
|
53 |
#define VIRTIO_PCI_ABI_VERSION 0 |
54 |
|
55 |
/* How many bits to shift physical queue address written to QUEUE_PFN.
|
56 |
* 12 is historical, and due to x86 page size. */
|
57 |
#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 |
58 |
|
59 |
/* QEMU doesn't strictly need write barriers since everything runs in
|
60 |
* lock-step. We'll leave the calls to wmb() in though to make it obvious for
|
61 |
* KVM or if kqemu gets SMP support.
|
62 |
*/
|
63 |
#define wmb() do { } while (0) |
64 |
|
65 |
/* PCI bindings. */
|
66 |
|
67 |
typedef struct { |
68 |
PCIDevice pci_dev; |
69 |
VirtIODevice *vdev; |
70 |
uint32_t addr; |
71 |
|
72 |
uint16_t vendor; |
73 |
uint16_t device; |
74 |
uint16_t subvendor; |
75 |
uint16_t class_code; |
76 |
uint8_t pif; |
77 |
} VirtIOPCIProxy; |
78 |
|
79 |
/* virtio device */
|
80 |
|
81 |
static void virtio_pci_update_irq(void *opaque) |
82 |
{ |
83 |
VirtIOPCIProxy *proxy = opaque; |
84 |
|
85 |
qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1); |
86 |
} |
87 |
|
88 |
static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
89 |
{ |
90 |
VirtIOPCIProxy *proxy = opaque; |
91 |
VirtIODevice *vdev = proxy->vdev; |
92 |
target_phys_addr_t pa; |
93 |
|
94 |
addr -= proxy->addr; |
95 |
|
96 |
switch (addr) {
|
97 |
case VIRTIO_PCI_GUEST_FEATURES:
|
98 |
/* Guest does not negotiate properly? We have to assume nothing. */
|
99 |
if (val & (1 << VIRTIO_F_BAD_FEATURE)) { |
100 |
if (vdev->bad_features)
|
101 |
val = vdev->bad_features(vdev); |
102 |
else
|
103 |
val = 0;
|
104 |
} |
105 |
if (vdev->set_features)
|
106 |
vdev->set_features(vdev, val); |
107 |
vdev->features = val; |
108 |
break;
|
109 |
case VIRTIO_PCI_QUEUE_PFN:
|
110 |
pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
111 |
virtio_queue_set_addr(vdev, vdev->queue_sel, pa); |
112 |
break;
|
113 |
case VIRTIO_PCI_QUEUE_SEL:
|
114 |
if (val < VIRTIO_PCI_QUEUE_MAX)
|
115 |
vdev->queue_sel = val; |
116 |
break;
|
117 |
case VIRTIO_PCI_QUEUE_NOTIFY:
|
118 |
virtio_queue_notify(vdev, val); |
119 |
break;
|
120 |
case VIRTIO_PCI_STATUS:
|
121 |
vdev->status = val & 0xFF;
|
122 |
if (vdev->status == 0) |
123 |
virtio_reset(vdev); |
124 |
break;
|
125 |
} |
126 |
} |
127 |
|
128 |
static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) |
129 |
{ |
130 |
VirtIOPCIProxy *proxy = opaque; |
131 |
VirtIODevice *vdev = proxy->vdev; |
132 |
uint32_t ret = 0xFFFFFFFF;
|
133 |
|
134 |
addr -= proxy->addr; |
135 |
|
136 |
switch (addr) {
|
137 |
case VIRTIO_PCI_HOST_FEATURES:
|
138 |
ret = vdev->get_features(vdev); |
139 |
ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE); |
140 |
break;
|
141 |
case VIRTIO_PCI_GUEST_FEATURES:
|
142 |
ret = vdev->features; |
143 |
break;
|
144 |
case VIRTIO_PCI_QUEUE_PFN:
|
145 |
ret = virtio_queue_get_addr(vdev, vdev->queue_sel) |
146 |
>> VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
147 |
break;
|
148 |
case VIRTIO_PCI_QUEUE_NUM:
|
149 |
ret = virtio_queue_get_num(vdev, vdev->queue_sel); |
150 |
break;
|
151 |
case VIRTIO_PCI_QUEUE_SEL:
|
152 |
ret = vdev->queue_sel; |
153 |
break;
|
154 |
case VIRTIO_PCI_STATUS:
|
155 |
ret = vdev->status; |
156 |
break;
|
157 |
case VIRTIO_PCI_ISR:
|
158 |
/* reading from the ISR also clears it. */
|
159 |
ret = vdev->isr; |
160 |
vdev->isr = 0;
|
161 |
virtio_update_irq(vdev); |
162 |
break;
|
163 |
default:
|
164 |
break;
|
165 |
} |
166 |
|
167 |
return ret;
|
168 |
} |
169 |
|
170 |
static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr) |
171 |
{ |
172 |
VirtIOPCIProxy *proxy = opaque; |
173 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
174 |
return virtio_config_readb(proxy->vdev, addr);
|
175 |
} |
176 |
|
177 |
static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) |
178 |
{ |
179 |
VirtIOPCIProxy *proxy = opaque; |
180 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
181 |
return virtio_config_readw(proxy->vdev, addr);
|
182 |
} |
183 |
|
184 |
static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) |
185 |
{ |
186 |
VirtIOPCIProxy *proxy = opaque; |
187 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
188 |
return virtio_config_readl(proxy->vdev, addr);
|
189 |
} |
190 |
|
191 |
static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val) |
192 |
{ |
193 |
VirtIOPCIProxy *proxy = opaque; |
194 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
195 |
virtio_config_writeb(proxy->vdev, addr, val); |
196 |
} |
197 |
|
198 |
static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val) |
199 |
{ |
200 |
VirtIOPCIProxy *proxy = opaque; |
201 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
202 |
virtio_config_writew(proxy->vdev, addr, val); |
203 |
} |
204 |
|
205 |
static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) |
206 |
{ |
207 |
VirtIOPCIProxy *proxy = opaque; |
208 |
addr -= proxy->addr + VIRTIO_PCI_CONFIG; |
209 |
virtio_config_writel(proxy->vdev, addr, val); |
210 |
} |
211 |
|
212 |
static void virtio_map(PCIDevice *pci_dev, int region_num, |
213 |
uint32_t addr, uint32_t size, int type)
|
214 |
{ |
215 |
VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev); |
216 |
VirtIODevice *vdev = proxy->vdev; |
217 |
int i;
|
218 |
|
219 |
proxy->addr = addr; |
220 |
for (i = 0; i < 3; i++) { |
221 |
register_ioport_write(addr, VIRTIO_PCI_CONFIG, 1 << i,
|
222 |
virtio_ioport_write, proxy); |
223 |
register_ioport_read(addr, VIRTIO_PCI_CONFIG, 1 << i,
|
224 |
virtio_ioport_read, proxy); |
225 |
} |
226 |
|
227 |
if (vdev->config_len) {
|
228 |
register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 1,
|
229 |
virtio_pci_config_writeb, proxy); |
230 |
register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 2,
|
231 |
virtio_pci_config_writew, proxy); |
232 |
register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 4,
|
233 |
virtio_pci_config_writel, proxy); |
234 |
register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 1,
|
235 |
virtio_pci_config_readb, proxy); |
236 |
register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 2,
|
237 |
virtio_pci_config_readw, proxy); |
238 |
register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 4,
|
239 |
virtio_pci_config_readl, proxy); |
240 |
|
241 |
vdev->get_config(vdev, vdev->config); |
242 |
} |
243 |
} |
244 |
|
245 |
static const VirtIOBindings virtio_pci_bindings = { |
246 |
.update_irq = virtio_pci_update_irq |
247 |
}; |
248 |
|
249 |
static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev, |
250 |
uint16_t vendor, uint16_t device, |
251 |
uint16_t class_code, uint8_t pif) |
252 |
{ |
253 |
uint8_t *config; |
254 |
uint32_t size; |
255 |
|
256 |
proxy->vdev = vdev; |
257 |
|
258 |
config = proxy->pci_dev.config; |
259 |
pci_config_set_vendor_id(config, vendor); |
260 |
pci_config_set_device_id(config, device); |
261 |
|
262 |
config[0x08] = VIRTIO_PCI_ABI_VERSION;
|
263 |
|
264 |
config[0x09] = pif;
|
265 |
pci_config_set_class(config, class_code); |
266 |
config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; |
267 |
|
268 |
config[0x2c] = vendor & 0xFF; |
269 |
config[0x2d] = (vendor >> 8) & 0xFF; |
270 |
config[0x2e] = vdev->device_id & 0xFF; |
271 |
config[0x2f] = (vdev->device_id >> 8) & 0xFF; |
272 |
|
273 |
config[0x3d] = 1; |
274 |
|
275 |
size = 20 + vdev->config_len;
|
276 |
if (size & (size-1)) |
277 |
size = 1 << qemu_fls(size);
|
278 |
|
279 |
pci_register_io_region(&proxy->pci_dev, 0, size, PCI_ADDRESS_SPACE_IO,
|
280 |
virtio_map); |
281 |
|
282 |
virtio_bind_device(vdev, &virtio_pci_bindings, proxy); |
283 |
} |
284 |
|
285 |
static void virtio_blk_init_pci(PCIDevice *pci_dev) |
286 |
{ |
287 |
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
288 |
VirtIODevice *vdev; |
289 |
|
290 |
vdev = virtio_blk_init(&pci_dev->qdev); |
291 |
virtio_init_pci(proxy, vdev, |
292 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
293 |
PCI_DEVICE_ID_VIRTIO_BLOCK, |
294 |
PCI_CLASS_STORAGE_OTHER, |
295 |
0x00);
|
296 |
} |
297 |
|
298 |
static void virtio_console_init_pci(PCIDevice *pci_dev) |
299 |
{ |
300 |
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
301 |
VirtIODevice *vdev; |
302 |
|
303 |
vdev = virtio_console_init(&pci_dev->qdev); |
304 |
virtio_init_pci(proxy, vdev, |
305 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
306 |
PCI_DEVICE_ID_VIRTIO_CONSOLE, |
307 |
PCI_CLASS_DISPLAY_OTHER, |
308 |
0x00);
|
309 |
} |
310 |
|
311 |
static void virtio_net_init_pci(PCIDevice *pci_dev) |
312 |
{ |
313 |
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
314 |
VirtIODevice *vdev; |
315 |
|
316 |
vdev = virtio_net_init(&pci_dev->qdev); |
317 |
virtio_init_pci(proxy, vdev, |
318 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
319 |
PCI_DEVICE_ID_VIRTIO_NET, |
320 |
PCI_CLASS_NETWORK_ETHERNET, |
321 |
0x00);
|
322 |
} |
323 |
|
324 |
static void virtio_balloon_init_pci(PCIDevice *pci_dev) |
325 |
{ |
326 |
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); |
327 |
VirtIODevice *vdev; |
328 |
|
329 |
vdev = virtio_balloon_init(&pci_dev->qdev); |
330 |
virtio_init_pci(proxy, vdev, |
331 |
PCI_VENDOR_ID_REDHAT_QUMRANET, |
332 |
PCI_DEVICE_ID_VIRTIO_BALLOON, |
333 |
PCI_CLASS_MEMORY_RAM, |
334 |
0x00);
|
335 |
} |
336 |
|
337 |
static void virtio_pci_register_devices(void) |
338 |
{ |
339 |
pci_qdev_register("virtio-blk-pci", sizeof(VirtIOPCIProxy), |
340 |
virtio_blk_init_pci); |
341 |
pci_qdev_register("virtio-net-pci", sizeof(VirtIOPCIProxy), |
342 |
virtio_net_init_pci); |
343 |
pci_qdev_register("virtio-console-pci", sizeof(VirtIOPCIProxy), |
344 |
virtio_console_init_pci); |
345 |
pci_qdev_register("virtio-balloon-pci", sizeof(VirtIOPCIProxy), |
346 |
virtio_balloon_init_pci); |
347 |
} |
348 |
|
349 |
device_init(virtio_pci_register_devices) |