|
1 /* |
|
2 * Virtio PCI bindings |
|
3 * |
|
4 * Copyright IBM, Corp. 2007 |
|
5 * |
|
6 * Authors: |
|
7 * Anthony Liguori <aliguori@us.ibm.com> |
|
8 * |
|
9 * This work is licensed under the terms of the GNU GPL, version 2. See |
|
10 * the COPYING file in the top-level directory. |
|
11 * |
|
12 */ |
|
13 |
|
14 #include "virtio-pci.h" |
|
15 #include "virtio-blk.h" |
|
16 #include "virtio-net.h" |
|
17 #include "virtio-balloon.h" |
|
18 |
|
19 /* from Linux's linux/virtio_pci.h */ |
|
20 |
|
21 /* A 32-bit r/o bitmask of the features supported by the host */ |
|
22 #define VIRTIO_PCI_HOST_FEATURES 0 |
|
23 |
|
24 /* A 32-bit r/w bitmask of features activated by the guest */ |
|
25 #define VIRTIO_PCI_GUEST_FEATURES 4 |
|
26 |
|
27 /* A 32-bit r/w PFN for the currently selected queue */ |
|
28 #define VIRTIO_PCI_QUEUE_PFN 8 |
|
29 |
|
30 /* A 16-bit r/o queue size for the currently selected queue */ |
|
31 #define VIRTIO_PCI_QUEUE_NUM 12 |
|
32 |
|
33 /* A 16-bit r/w queue selector */ |
|
34 #define VIRTIO_PCI_QUEUE_SEL 14 |
|
35 |
|
36 /* A 16-bit r/w queue notifier */ |
|
37 #define VIRTIO_PCI_QUEUE_NOTIFY 16 |
|
38 |
|
39 /* An 8-bit device status register. */ |
|
40 #define VIRTIO_PCI_STATUS 18 |
|
41 |
|
42 /* An 8-bit r/o interrupt status register. Reading the value will return the |
|
43 * current contents of the ISR and will also clear it. This is effectively |
|
44 * a read-and-acknowledge. */ |
|
45 #define VIRTIO_PCI_ISR 19 |
|
46 |
|
47 #define VIRTIO_PCI_CONFIG 20 |
|
48 |
|
49 /* Virtio ABI version, if we increment this, we break the guest driver. */ |
|
50 #define VIRTIO_PCI_ABI_VERSION 0 |
|
51 |
|
52 /* How many bits to shift physical queue address written to QUEUE_PFN. |
|
53 * 12 is historical, and due to x86 page size. */ |
|
54 #define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 |
|
55 |
|
56 /* Proxy device to link the PCIDevice to the VirtIODevice. */ |
|
57 typedef struct { |
|
58 PCIDevice pci_dev; |
|
59 VirtIODevice *vdev; |
|
60 } VirtIOPCIProxy; |
|
61 |
|
62 /* Device independent interface code. */ |
|
63 |
|
64 static VirtIODevice *to_virtio_device(PCIDevice *pci_dev) |
|
65 { |
|
66 VirtIOPCIProxy *proxy = (VirtIOPCIProxy *)pci_dev; |
|
67 return proxy->vdev; |
|
68 } |
|
69 |
|
70 static void virtio_update_irq_pci(VirtIODevice *vdev) |
|
71 { |
|
72 PCIDevice *pci_dev = (PCIDevice *)vdev->binding_dev; |
|
73 qemu_set_irq(pci_dev->irq[0], vdev->isr & 1); |
|
74 } |
|
75 |
|
76 static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
|
77 { |
|
78 VirtIODevice *vdev = to_virtio_device(opaque); |
|
79 target_phys_addr_t pa; |
|
80 |
|
81 addr -= vdev->addr; |
|
82 |
|
83 switch (addr) { |
|
84 case VIRTIO_PCI_GUEST_FEATURES: |
|
85 if (vdev->set_features) |
|
86 vdev->set_features(vdev, val); |
|
87 vdev->features = val; |
|
88 break; |
|
89 case VIRTIO_PCI_QUEUE_PFN: |
|
90 pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
|
91 virtio_set_vring_addr(vdev, vdev->queue_sel, pa); |
|
92 case VIRTIO_PCI_QUEUE_SEL: |
|
93 if (val < VIRTIO_PCI_QUEUE_MAX) |
|
94 vdev->queue_sel = val; |
|
95 break; |
|
96 case VIRTIO_PCI_QUEUE_NOTIFY: |
|
97 virtio_kick(vdev, val); |
|
98 break; |
|
99 case VIRTIO_PCI_STATUS: |
|
100 vdev->status = val & 0xFF; |
|
101 if (vdev->status == 0) |
|
102 virtio_reset(vdev); |
|
103 break; |
|
104 } |
|
105 } |
|
106 |
|
107 static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) |
|
108 { |
|
109 VirtIODevice *vdev = to_virtio_device(opaque); |
|
110 uint32_t ret = 0xFFFFFFFF; |
|
111 |
|
112 addr -= vdev->addr; |
|
113 |
|
114 switch (addr) { |
|
115 case VIRTIO_PCI_HOST_FEATURES: |
|
116 ret = vdev->get_features(vdev); |
|
117 ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); |
|
118 break; |
|
119 case VIRTIO_PCI_GUEST_FEATURES: |
|
120 ret = vdev->features; |
|
121 break; |
|
122 case VIRTIO_PCI_QUEUE_PFN: |
|
123 ret = virtio_get_vring_pa(vdev, vdev->queue_sel) |
|
124 >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
|
125 break; |
|
126 case VIRTIO_PCI_QUEUE_NUM: |
|
127 ret = virtio_get_vring_num(vdev, vdev->queue_sel); |
|
128 break; |
|
129 case VIRTIO_PCI_QUEUE_SEL: |
|
130 ret = vdev->queue_sel; |
|
131 break; |
|
132 case VIRTIO_PCI_STATUS: |
|
133 ret = vdev->status; |
|
134 break; |
|
135 case VIRTIO_PCI_ISR: |
|
136 /* reading from the ISR also clears it. */ |
|
137 ret = vdev->isr; |
|
138 vdev->isr = 0; |
|
139 virtio_update_irq(vdev); |
|
140 break; |
|
141 default: |
|
142 break; |
|
143 } |
|
144 |
|
145 return ret; |
|
146 } |
|
147 |
|
148 static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr) |
|
149 { |
|
150 VirtIODevice *vdev = opaque; |
|
151 |
|
152 addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
153 return virtio_config_readb(vdev, addr); |
|
154 } |
|
155 |
|
156 static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) |
|
157 { |
|
158 VirtIODevice *vdev = opaque; |
|
159 |
|
160 addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
161 return virtio_config_readw(vdev, addr); |
|
162 } |
|
163 |
|
164 static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) |
|
165 { |
|
166 VirtIODevice *vdev = opaque; |
|
167 |
|
168 addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
169 return virtio_config_readl(vdev, addr); |
|
170 } |
|
171 |
|
172 static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t data) |
|
173 { |
|
174 VirtIODevice *vdev = opaque; |
|
175 |
|
176 addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
177 virtio_config_writeb(vdev, addr, data); |
|
178 } |
|
179 |
|
180 static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t data) |
|
181 { |
|
182 VirtIODevice *vdev = opaque; |
|
183 |
|
184 addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
185 virtio_config_writew(vdev, addr, data); |
|
186 } |
|
187 |
|
188 static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t data) |
|
189 { |
|
190 VirtIODevice *vdev = opaque; |
|
191 |
|
192 addr -= vdev->addr + VIRTIO_PCI_CONFIG; |
|
193 virtio_config_writel(vdev, addr, data); |
|
194 } |
|
195 |
|
196 static void virtio_map(PCIDevice *pci_dev, int region_num, |
|
197 uint32_t addr, uint32_t size, int type) |
|
198 { |
|
199 VirtIODevice *vdev = to_virtio_device(pci_dev); |
|
200 int i; |
|
201 |
|
202 vdev->addr = addr; |
|
203 for (i = 0; i < 3; i++) { |
|
204 register_ioport_write(addr, 20, 1 << i, virtio_ioport_write, vdev); |
|
205 register_ioport_read(addr, 20, 1 << i, virtio_ioport_read, vdev); |
|
206 } |
|
207 |
|
208 if (vdev->config_len) { |
|
209 register_ioport_write(addr + 20, vdev->config_len, 1, |
|
210 virtio_pci_config_writeb, vdev); |
|
211 register_ioport_write(addr + 20, vdev->config_len, 2, |
|
212 virtio_pci_config_writew, vdev); |
|
213 register_ioport_write(addr + 20, vdev->config_len, 4, |
|
214 virtio_pci_config_writel, vdev); |
|
215 register_ioport_read(addr + 20, vdev->config_len, 1, |
|
216 virtio_pci_config_readb, vdev); |
|
217 register_ioport_read(addr + 20, vdev->config_len, 2, |
|
218 virtio_pci_config_readw, vdev); |
|
219 register_ioport_read(addr + 20, vdev->config_len, 4, |
|
220 virtio_pci_config_readl, vdev); |
|
221 |
|
222 vdev->get_config(vdev, vdev->config); |
|
223 } |
|
224 } |
|
225 |
|
226 static void virtio_save_pci(VirtIODevice *vdev, QEMUFile *f) |
|
227 { |
|
228 pci_device_save((PCIDevice *)vdev->binding_dev, f); |
|
229 } |
|
230 |
|
231 static void virtio_load_pci(VirtIODevice *vdev, QEMUFile *f) |
|
232 { |
|
233 pci_device_load((PCIDevice *)vdev->binding_dev, f); |
|
234 } |
|
235 |
|
236 /* FIXME: PCI bindings should go elsewhere. */ |
|
237 typedef struct { |
|
238 PCIBus *bus; |
|
239 int devfn; |
|
240 uint16_t vendor; |
|
241 uint16_t device; |
|
242 uint16_t class_code; |
|
243 uint16_t subclass_code; |
|
244 uint8_t pif; |
|
245 } VirtIOPCIArgs; |
|
246 |
|
247 static VirtIODevice *virtio_init_pci(void *args, const char *name, |
|
248 uint16_t vendor, uint16_t device, |
|
249 size_t config_size, size_t struct_size) |
|
250 { |
|
251 VirtIODevice *vdev; |
|
252 PCIDevice *pci_dev; |
|
253 VirtIOPCIArgs *p = args; |
|
254 uint8_t *config; |
|
255 uint32_t size; |
|
256 |
|
257 pci_dev = pci_register_device(p->bus, name, sizeof(VirtIOPCIProxy), |
|
258 p->devfn, NULL, NULL); |
|
259 if (!pci_dev) |
|
260 return NULL; |
|
261 |
|
262 vdev = virtio_init_common(name, config_size, struct_size); |
|
263 ((VirtIOPCIProxy *)pci_dev)->vdev = vdev; |
|
264 |
|
265 vdev->binding_dev = pci_dev; |
|
266 vdev->update_irq = virtio_update_irq_pci; |
|
267 vdev->save_binding = virtio_save_pci; |
|
268 vdev->load_binding = virtio_load_pci; |
|
269 |
|
270 config = pci_dev->config; |
|
271 config[0x00] = p->vendor & 0xFF; |
|
272 config[0x01] = (p->vendor >> 8) & 0xFF; |
|
273 config[0x02] = p->device & 0xFF; |
|
274 config[0x03] = (p->device >> 8) & 0xFF; |
|
275 |
|
276 config[0x08] = VIRTIO_PCI_ABI_VERSION; |
|
277 |
|
278 config[0x09] = p->pif; |
|
279 config[0x0a] = p->subclass_code; |
|
280 config[0x0b] = p->class_code; |
|
281 config[0x0e] = 0x00; |
|
282 |
|
283 config[0x2c] = vendor & 0xFF; |
|
284 config[0x2d] = (vendor >> 8) & 0xFF; |
|
285 config[0x2e] = device & 0xFF; |
|
286 config[0x2f] = (device >> 8) & 0xFF; |
|
287 |
|
288 config[0x3d] = 1; |
|
289 |
|
290 size = 20 + config_size; |
|
291 if (size & (size-1)) |
|
292 size = 1 << qemu_fls(size); |
|
293 |
|
294 pci_register_io_region(pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, |
|
295 virtio_map); |
|
296 |
|
297 return vdev; |
|
298 } |
|
299 |
|
300 |
|
301 /* Device specific init routines. */ |
|
302 |
|
303 void virtio_blk_init_pci(PCIBus *bus, BlockDriverState *bs) |
|
304 { |
|
305 VirtIOPCIArgs args; |
|
306 args.bus = bus; |
|
307 args.devfn = -1; |
|
308 args.vendor = PCI_VENDOR_ID_REDHAT_QUMRANET; |
|
309 args.device = PCI_DEVICE_ID_VIRTIO_BLOCK; |
|
310 args.class_code = 0x01; |
|
311 args.subclass_code = 0x80; |
|
312 args.pif = 0x00; |
|
313 virtio_blk_init(virtio_init_pci, &args, bs); |
|
314 } |
|
315 |
|
316 void virtio_net_init_pci(PCIBus *bus, NICInfo *nd, int devfn) |
|
317 { |
|
318 VirtIOPCIArgs args; |
|
319 args.bus = bus; |
|
320 args.devfn = devfn; |
|
321 args.vendor = PCI_VENDOR_ID_REDHAT_QUMRANET; |
|
322 args.device = PCI_DEVICE_ID_VIRTIO_NET; |
|
323 args.class_code = 0x02; |
|
324 args.subclass_code = 0x00; |
|
325 args.pif = 0x00; |
|
326 virtio_net_init(virtio_init_pci, &args, nd); |
|
327 } |
|
328 |
|
329 void virtio_balloon_init_pci(PCIBus *bus) |
|
330 { |
|
331 VirtIOPCIArgs args; |
|
332 args.bus = bus; |
|
333 args.devfn = -1; |
|
334 args.vendor = PCI_VENDOR_ID_REDHAT_QUMRANET; |
|
335 args.device = PCI_DEVICE_ID_VIRTIO_BALLOON; |
|
336 args.class_code = 0x05; |
|
337 args.subclass_code = 0x00; |
|
338 args.pif = 0x00; |
|
339 virtio_balloon_init(virtio_init_pci, &args); |
|
340 } |