1 /*
2 * Virtio PCI driver - modern (virtio 1.0) device support
3 *
4 * Copyright IBM Corp. 2007
5 * Copyright Red Hat, Inc. 2014
6 *
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>
9 * Rusty Russell <rusty@rustcorp.com.au>
10 * Michael S. Tsirkin <mst@redhat.com>
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met :
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and / or other materials provided with the distribution.
20 * 3. Neither the names of the copyright holders nor the names of their contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35 #include "osdep.h"
36 #define VIRTIO_PCI_NO_LEGACY
37 #include "virtio_pci.h"
38 #include "VirtIO.h"
39 #include "kdebugprint.h"
40 #include "virtio_ring.h"
41 #include "virtio_pci_common.h"
42 #include "windows/virtio_ring_allocation.h"
43 #include <stddef.h>
44
45 #ifdef WPP_EVENT_TRACING
46 #include "VirtIOPCIModern.tmh"
47 #endif
48
vio_modern_map_capability(VirtIODevice * vdev,int cap_offset,size_t minlen,u32 alignment,u32 start,u32 size,size_t * len)49 static void *vio_modern_map_capability(VirtIODevice *vdev, int cap_offset,
50 size_t minlen, u32 alignment,
51 u32 start, u32 size, size_t *len)
52 {
53 u8 bar;
54 u32 bar_offset, bar_length;
55 void *addr;
56
57 pci_read_config_byte(vdev, cap_offset + offsetof(struct virtio_pci_cap, bar), &bar);
58 pci_read_config_dword(vdev, cap_offset + offsetof(struct virtio_pci_cap, offset), &bar_offset);
59 pci_read_config_dword(vdev, cap_offset + offsetof(struct virtio_pci_cap, length), &bar_length);
60
61 if (start + minlen > bar_length) {
62 DPrintf(0, "bar %i cap is not large enough to map %zu bytes at offset %u\n", bar, minlen, start);
63 return NULL;
64 }
65
66 bar_length -= start;
67 bar_offset += start;
68
69 if (bar_offset & (alignment - 1)) {
70 DPrintf(0, "bar %i offset %u not aligned to %u\n", bar, bar_offset, alignment);
71 return NULL;
72 }
73
74 if (bar_length > size) {
75 bar_length = size;
76 }
77
78 if (len) {
79 *len = bar_length;
80 }
81
82 if (bar_offset + minlen > pci_get_resource_len(vdev, bar)) {
83 DPrintf(0, "bar %i is not large enough to map %zu bytes at offset %u\n", bar, minlen, bar_offset);
84 return NULL;
85 }
86
87 addr = pci_map_address_range(vdev, bar, bar_offset, bar_length);
88 if (!addr) {
89 DPrintf(0, "unable to map %u bytes at bar %i offset %u\n", bar_length, bar, bar_offset);
90 }
91 return addr;
92 }
93
vio_modern_map_simple_capability(VirtIODevice * vdev,int cap_offset,size_t length,u32 alignment)94 static void *vio_modern_map_simple_capability(VirtIODevice *vdev, int cap_offset, size_t length, u32 alignment)
95 {
96 return vio_modern_map_capability(
97 vdev,
98 cap_offset,
99 length, // minlen
100 alignment,
101 0, // offset
102 (u32)length, // size is equal to minlen
103 NULL); // not interested in the full length
104 }
105
vio_modern_get_config(VirtIODevice * vdev,unsigned offset,void * buf,unsigned len)106 static void vio_modern_get_config(VirtIODevice *vdev, unsigned offset,
107 void *buf, unsigned len)
108 {
109 if (!vdev->config) {
110 ASSERT(!"Device has no config to read");
111 return;
112 }
113 if (offset + len > vdev->config_len) {
114 ASSERT(!"Can't read beyond the config length");
115 return;
116 }
117
118 switch (len) {
119 case 1:
120 *(u8 *)buf = ioread8(vdev, vdev->config + offset);
121 break;
122 case 2:
123 *(u16 *)buf = ioread16(vdev, vdev->config + offset);
124 break;
125 case 4:
126 *(u32 *)buf = ioread32(vdev, vdev->config + offset);
127 break;
128 default:
129 ASSERT(!"Only 1, 2, 4 byte config reads are supported");
130 }
131 }
132
vio_modern_set_config(VirtIODevice * vdev,unsigned offset,const void * buf,unsigned len)133 static void vio_modern_set_config(VirtIODevice *vdev, unsigned offset,
134 const void *buf, unsigned len)
135 {
136 if (!vdev->config) {
137 ASSERT(!"Device has no config to write");
138 return;
139 }
140 if (offset + len > vdev->config_len) {
141 ASSERT(!"Can't write beyond the config length");
142 return;
143 }
144
145 switch (len) {
146 case 1:
147 iowrite8(vdev, *(u8 *)buf, vdev->config + offset);
148 break;
149 case 2:
150 iowrite16(vdev, *(u16 *)buf, vdev->config + offset);
151 break;
152 case 4:
153 iowrite32(vdev, *(u32 *)buf, vdev->config + offset);
154 break;
155 default:
156 ASSERT(!"Only 1, 2, 4 byte config writes are supported");
157 }
158 }
159
vio_modern_get_generation(VirtIODevice * vdev)160 static u32 vio_modern_get_generation(VirtIODevice *vdev)
161 {
162 return ioread8(vdev, &vdev->common->config_generation);
163 }
164
vio_modern_get_status(VirtIODevice * vdev)165 static u8 vio_modern_get_status(VirtIODevice *vdev)
166 {
167 return ioread8(vdev, &vdev->common->device_status);
168 }
169
vio_modern_set_status(VirtIODevice * vdev,u8 status)170 static void vio_modern_set_status(VirtIODevice *vdev, u8 status)
171 {
172 /* We should never be setting status to 0. */
173 ASSERT(status != 0);
174 iowrite8(vdev, status, &vdev->common->device_status);
175 }
176
vio_modern_reset(VirtIODevice * vdev)177 static void vio_modern_reset(VirtIODevice *vdev)
178 {
179 /* 0 status means a reset. */
180 iowrite8(vdev, 0, &vdev->common->device_status);
181 /* After writing 0 to device_status, the driver MUST wait for a read of
182 * device_status to return 0 before reinitializing the device.
183 * This will flush out the status write, and flush in device writes,
184 * including MSI-X interrupts, if any.
185 */
186 while (ioread8(vdev, &vdev->common->device_status)) {
187 u16 val;
188 if (pci_read_config_word(vdev, 0, &val) || val == 0xffff) {
189 DPrintf(0, "PCI config space is not readable, probably the device is removed\n", 0);
190 break;
191 }
192 vdev_sleep(vdev, 1);
193 }
194 }
195
vio_modern_get_features(VirtIODevice * vdev)196 static u64 vio_modern_get_features(VirtIODevice *vdev)
197 {
198 u64 features;
199
200 iowrite32(vdev, 0, &vdev->common->device_feature_select);
201 features = ioread32(vdev, &vdev->common->device_feature);
202 iowrite32(vdev, 1, &vdev->common->device_feature_select);
203 features |= ((u64)ioread32(vdev, &vdev->common->device_feature) << 32);
204
205 return features;
206 }
207
vio_modern_set_features(VirtIODevice * vdev,u64 features)208 static NTSTATUS vio_modern_set_features(VirtIODevice *vdev, u64 features)
209 {
210 /* Give virtio_ring a chance to accept features. */
211 vring_transport_features(vdev, &features);
212
213 if (!virtio_is_feature_enabled(features, VIRTIO_F_VERSION_1)) {
214 DPrintf(0, "virtio: device uses modern interface but does not have VIRTIO_F_VERSION_1\n", 0);
215 return STATUS_INVALID_PARAMETER;
216 }
217
218 iowrite32(vdev, 0, &vdev->common->guest_feature_select);
219 iowrite32(vdev, (u32)features, &vdev->common->guest_feature);
220 iowrite32(vdev, 1, &vdev->common->guest_feature_select);
221 iowrite32(vdev, features >> 32, &vdev->common->guest_feature);
222
223 return STATUS_SUCCESS;
224 }
225
vio_modern_set_config_vector(VirtIODevice * vdev,u16 vector)226 static u16 vio_modern_set_config_vector(VirtIODevice *vdev, u16 vector)
227 {
228 /* Setup the vector used for configuration events */
229 iowrite16(vdev, vector, &vdev->common->msix_config);
230 /* Verify we had enough resources to assign the vector */
231 /* Will also flush the write out to device */
232 return ioread16(vdev, &vdev->common->msix_config);
233 }
234
vio_modern_set_queue_vector(struct virtqueue * vq,u16 vector)235 static u16 vio_modern_set_queue_vector(struct virtqueue *vq, u16 vector)
236 {
237 VirtIODevice *vdev = vq->vdev;
238 volatile struct virtio_pci_common_cfg *cfg = vdev->common;
239
240 iowrite16(vdev, (u16)vq->index, &cfg->queue_select);
241 iowrite16(vdev, vector, &cfg->queue_msix_vector);
242 return ioread16(vdev, &cfg->queue_msix_vector);
243 }
244
vring_pci_size(u16 num,bool packed)245 static size_t vring_pci_size(u16 num, bool packed)
246 {
247 /* We only need a cacheline separation. */
248 return (size_t)ROUND_TO_PAGES(vring_size(num, SMP_CACHE_BYTES, packed));
249 }
250
vio_modern_query_vq_alloc(VirtIODevice * vdev,unsigned index,unsigned short * pNumEntries,unsigned long * pRingSize,unsigned long * pHeapSize)251 static NTSTATUS vio_modern_query_vq_alloc(VirtIODevice *vdev,
252 unsigned index,
253 unsigned short *pNumEntries,
254 unsigned long *pRingSize,
255 unsigned long *pHeapSize)
256 {
257 volatile struct virtio_pci_common_cfg *cfg = vdev->common;
258 u16 num;
259
260 if (index >= ioread16(vdev, &cfg->num_queues)) {
261 return STATUS_NOT_FOUND;
262 }
263
264 /* Select the queue we're interested in */
265 iowrite16(vdev, (u16)index, &cfg->queue_select);
266
267 /* Check if queue is either not available or already active. */
268 num = ioread16(vdev, &cfg->queue_size);
269 /* QEMU has a bug where queues don't revert to inactive on device
270 * reset. Skip checking the queue_enable field until it is fixed.
271 */
272 if (!num /*|| ioread16(vdev, &cfg->queue_enable)*/) {
273 return STATUS_NOT_FOUND;
274 }
275
276 if (num & (num - 1)) {
277 DPrintf(0, "%p: bad queue size %u", vdev, num);
278 return STATUS_INVALID_PARAMETER;
279 }
280
281 *pNumEntries = num;
282 *pRingSize = (unsigned long)vring_pci_size(num, vdev->packed_ring);
283 *pHeapSize = vring_control_block_size(num, vdev->packed_ring);
284
285 return STATUS_SUCCESS;
286 }
287
vio_modern_setup_vq(struct virtqueue ** queue,VirtIODevice * vdev,VirtIOQueueInfo * info,unsigned index,u16 msix_vec)288 static NTSTATUS vio_modern_setup_vq(struct virtqueue **queue,
289 VirtIODevice *vdev,
290 VirtIOQueueInfo *info,
291 unsigned index,
292 u16 msix_vec)
293 {
294 volatile struct virtio_pci_common_cfg *cfg = vdev->common;
295 struct virtqueue *vq;
296 void *vq_addr;
297 u16 off;
298 unsigned long ring_size, heap_size;
299 NTSTATUS status;
300
301 /* select the queue and query allocation parameters */
302 status = vio_modern_query_vq_alloc(vdev, index, &info->num, &ring_size, &heap_size);
303 if (!NT_SUCCESS(status)) {
304 return status;
305 }
306
307 /* get offset of notification word for this vq */
308 off = ioread16(vdev, &cfg->queue_notify_off);
309
310 /* try to allocate contiguous pages, scale down on failure */
311 while (!(info->queue = mem_alloc_contiguous_pages(vdev, vring_pci_size(info->num, vdev->packed_ring)))) {
312 if (info->num > 0) {
313 info->num /= 2;
314 } else {
315 return STATUS_INSUFFICIENT_RESOURCES;
316 }
317 }
318
319 vq_addr = mem_alloc_nonpaged_block(vdev, heap_size);
320 if (vq_addr == NULL) {
321 return STATUS_INSUFFICIENT_RESOURCES;
322 }
323
324 /* create the vring */
325 if (vdev->packed_ring) {
326 vq = vring_new_virtqueue_packed(index, info->num,
327 SMP_CACHE_BYTES, vdev,
328 info->queue, vp_notify, vq_addr);
329 } else {
330 vq = vring_new_virtqueue_split(index, info->num,
331 SMP_CACHE_BYTES, vdev,
332 info->queue, vp_notify, vq_addr);
333 }
334
335 if (!vq) {
336 status = STATUS_INSUFFICIENT_RESOURCES;
337 goto err_new_queue;
338 }
339
340 /* activate the queue */
341 iowrite16(vdev, info->num, &cfg->queue_size);
342 iowrite64_twopart(vdev, mem_get_physical_address(vdev, info->queue),
343 &cfg->queue_desc_lo, &cfg->queue_desc_hi);
344 iowrite64_twopart(vdev, mem_get_physical_address(vdev, vq->avail_va),
345 &cfg->queue_avail_lo, &cfg->queue_avail_hi);
346 iowrite64_twopart(vdev, mem_get_physical_address(vdev, vq->used_va),
347 &cfg->queue_used_lo, &cfg->queue_used_hi);
348
349 if (vdev->notify_base) {
350 /* offset should not wrap */
351 if ((u64)off * vdev->notify_offset_multiplier + 2
352 > vdev->notify_len) {
353 DPrintf(0,
354 "%p: bad notification offset %u (x %u) "
355 "for queue %u > %zd",
356 vdev,
357 off, vdev->notify_offset_multiplier,
358 index, vdev->notify_len);
359 status = STATUS_INVALID_PARAMETER;
360 goto err_map_notify;
361 }
362 vq->notification_addr = (void *)(vdev->notify_base +
363 off * vdev->notify_offset_multiplier);
364 } else {
365 vq->notification_addr = vio_modern_map_capability(vdev,
366 vdev->notify_map_cap, 2, 2,
367 off * vdev->notify_offset_multiplier, 2,
368 NULL);
369 }
370
371 if (!vq->notification_addr) {
372 status = STATUS_INSUFFICIENT_RESOURCES;
373 goto err_map_notify;
374 }
375
376 if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
377 msix_vec = vdev->device->set_queue_vector(vq, msix_vec);
378 if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
379 status = STATUS_DEVICE_BUSY;
380 goto err_assign_vector;
381 }
382 }
383
384 /* enable the queue */
385 iowrite16(vdev, 1, &vdev->common->queue_enable);
386
387 *queue = vq;
388 return STATUS_SUCCESS;
389
390 err_assign_vector:
391 err_map_notify:
392 virtqueue_shutdown(vq);
393 err_new_queue:
394 mem_free_nonpaged_block(vdev, vq_addr);
395 mem_free_contiguous_pages(vdev, info->queue);
396 return status;
397 }
398
vio_modern_del_vq(VirtIOQueueInfo * info)399 static void vio_modern_del_vq(VirtIOQueueInfo *info)
400 {
401 struct virtqueue *vq = info->vq;
402 VirtIODevice *vdev = vq->vdev;
403
404 iowrite16(vdev, (u16)vq->index, &vdev->common->queue_select);
405
406 if (vdev->msix_used) {
407 iowrite16(vdev, VIRTIO_MSI_NO_VECTOR, &vdev->common->queue_msix_vector);
408 /* Flush the write out to device */
409 ioread16(vdev, &vdev->common->queue_msix_vector);
410 }
411
412 virtqueue_shutdown(vq);
413
414 mem_free_nonpaged_block(vdev, vq);
415 mem_free_contiguous_pages(vdev, info->queue);
416 }
417
418 static const struct virtio_device_ops virtio_pci_device_ops = {
419 /* .get_config = */ vio_modern_get_config,
420 /* .set_config = */ vio_modern_set_config,
421 /* .get_config_generation = */ vio_modern_get_generation,
422 /* .get_status = */ vio_modern_get_status,
423 /* .set_status = */ vio_modern_set_status,
424 /* .reset = */ vio_modern_reset,
425 /* .get_features = */ vio_modern_get_features,
426 /* .set_features = */ vio_modern_set_features,
427 /* .set_config_vector = */ vio_modern_set_config_vector,
428 /* .set_queue_vector = */ vio_modern_set_queue_vector,
429 /* .query_queue_alloc = */ vio_modern_query_vq_alloc,
430 /* .setup_queue = */ vio_modern_setup_vq,
431 /* .delete_queue = */ vio_modern_del_vq,
432 };
433
find_next_pci_vendor_capability(VirtIODevice * vdev,u8 offset)434 static u8 find_next_pci_vendor_capability(VirtIODevice *vdev, u8 offset)
435 {
436 u8 id = 0;
437 int iterations = 48;
438
439 if (pci_read_config_byte(vdev, offset, &offset) != 0) {
440 return 0;
441 }
442
443 while (iterations-- && offset >= 0x40) {
444 offset &= ~3;
445 if (pci_read_config_byte(vdev, offset + offsetof(PCI_CAPABILITIES_HEADER,
446 CapabilityID), &id) != 0) {
447 break;
448 }
449 if (id == 0xFF) {
450 break;
451 }
452 if (id == PCI_CAPABILITY_ID_VENDOR_SPECIFIC) {
453 return offset;
454 }
455 if (pci_read_config_byte(vdev, offset + offsetof(PCI_CAPABILITIES_HEADER,
456 Next), &offset) != 0) {
457 break;
458 }
459 }
460 return 0;
461 }
462
find_first_pci_vendor_capability(VirtIODevice * vdev)463 static u8 find_first_pci_vendor_capability(VirtIODevice *vdev)
464 {
465 u8 hdr_type, offset;
466 u16 status;
467
468 if (pci_read_config_byte(vdev, offsetof(PCI_COMMON_HEADER, HeaderType), &hdr_type) != 0) {
469 return 0;
470 }
471 if (pci_read_config_word(vdev, offsetof(PCI_COMMON_HEADER, Status), &status) != 0) {
472 return 0;
473 }
474 if ((status & PCI_STATUS_CAPABILITIES_LIST) == 0) {
475 return 0;
476 }
477
478 switch (hdr_type & ~PCI_MULTIFUNCTION) {
479 case PCI_BRIDGE_TYPE:
480 offset = offsetof(PCI_COMMON_HEADER, u.type1.CapabilitiesPtr);
481 break;
482 case PCI_CARDBUS_BRIDGE_TYPE:
483 offset = offsetof(PCI_COMMON_HEADER, u.type2.CapabilitiesPtr);
484 break;
485 default:
486 offset = offsetof(PCI_COMMON_HEADER, u.type0.CapabilitiesPtr);
487 break;
488 }
489
490 if (offset != 0) {
491 offset = find_next_pci_vendor_capability(vdev, offset);
492 }
493 return offset;
494 }
495
496 /* Populate Offsets with virtio vendor capability offsets within the PCI config space */
find_pci_vendor_capabilities(VirtIODevice * vdev,int * Offsets,size_t nOffsets)497 static void find_pci_vendor_capabilities(VirtIODevice *vdev, int *Offsets, size_t nOffsets)
498 {
499 u8 offset = find_first_pci_vendor_capability(vdev);
500 while (offset > 0) {
501 u8 cfg_type, bar;
502 pci_read_config_byte(vdev, offset + offsetof(struct virtio_pci_cap, cfg_type), &cfg_type);
503 pci_read_config_byte(vdev, offset + offsetof(struct virtio_pci_cap, bar), &bar);
504
505 if (bar < PCI_TYPE0_ADDRESSES &&
506 cfg_type < nOffsets &&
507 pci_get_resource_len(vdev, bar) > 0) {
508 Offsets[cfg_type] = offset;
509 }
510
511 offset = find_next_pci_vendor_capability(vdev, offset + offsetof(PCI_CAPABILITIES_HEADER, Next));
512 }
513 }
514
515 /* Modern device initialization */
vio_modern_initialize(VirtIODevice * vdev)516 NTSTATUS vio_modern_initialize(VirtIODevice *vdev)
517 {
518 int capabilities[VIRTIO_PCI_CAP_PCI_CFG];
519
520 u32 notify_length;
521 u32 notify_offset;
522
523 RtlZeroMemory(capabilities, sizeof(capabilities));
524 find_pci_vendor_capabilities(vdev, capabilities, VIRTIO_PCI_CAP_PCI_CFG);
525
526 /* Check for a common config, if not found use legacy mode */
527 if (!capabilities[VIRTIO_PCI_CAP_COMMON_CFG]) {
528 DPrintf(0, "%s(%p): device not found\n", __FUNCTION__, vdev);
529 return STATUS_DEVICE_NOT_CONNECTED;
530 }
531
532 /* Check isr and notify caps, if not found fail */
533 if (!capabilities[VIRTIO_PCI_CAP_ISR_CFG] || !capabilities[VIRTIO_PCI_CAP_NOTIFY_CFG]) {
534 DPrintf(0, "%s(%p): missing capabilities %i/%i/%i\n",
535 __FUNCTION__, vdev,
536 capabilities[VIRTIO_PCI_CAP_COMMON_CFG],
537 capabilities[VIRTIO_PCI_CAP_ISR_CFG],
538 capabilities[VIRTIO_PCI_CAP_NOTIFY_CFG]);
539 return STATUS_INVALID_PARAMETER;
540 }
541
542 /* Map bars according to the capabilities */
543 vdev->common = vio_modern_map_simple_capability(vdev,
544 capabilities[VIRTIO_PCI_CAP_COMMON_CFG],
545 sizeof(struct virtio_pci_common_cfg), 4);
546 if (!vdev->common) {
547 return STATUS_INVALID_PARAMETER;
548 }
549
550 vdev->isr = vio_modern_map_simple_capability(vdev,
551 capabilities[VIRTIO_PCI_CAP_ISR_CFG],
552 sizeof(u8), 1);
553 if (!vdev->isr) {
554 return STATUS_INVALID_PARAMETER;
555 }
556
557 /* Read notify_off_multiplier from config space. */
558 pci_read_config_dword(vdev,
559 capabilities[VIRTIO_PCI_CAP_NOTIFY_CFG] + offsetof(struct virtio_pci_notify_cap,
560 notify_off_multiplier),
561 &vdev->notify_offset_multiplier);
562
563 /* Read notify length and offset from config space. */
564 pci_read_config_dword(vdev,
565 capabilities[VIRTIO_PCI_CAP_NOTIFY_CFG] + offsetof(struct virtio_pci_notify_cap,
566 cap.length),
567 ¬ify_length);
568 pci_read_config_dword(vdev,
569 capabilities[VIRTIO_PCI_CAP_NOTIFY_CFG] + offsetof(struct virtio_pci_notify_cap,
570 cap.offset),
571 ¬ify_offset);
572
573 /* Map the notify capability if it's small enough.
574 * Otherwise, map each VQ individually later.
575 */
576 if (notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) {
577 vdev->notify_base = vio_modern_map_capability(vdev,
578 capabilities[VIRTIO_PCI_CAP_NOTIFY_CFG], 2, 2,
579 0, notify_length,
580 &vdev->notify_len);
581 if (!vdev->notify_base) {
582 return STATUS_INVALID_PARAMETER;
583 }
584 } else {
585 vdev->notify_map_cap = capabilities[VIRTIO_PCI_CAP_NOTIFY_CFG];
586 }
587
588 /* Map the device config capability, the PAGE_SIZE size is a guess */
589 if (capabilities[VIRTIO_PCI_CAP_DEVICE_CFG]) {
590 vdev->config = vio_modern_map_capability(vdev,
591 capabilities[VIRTIO_PCI_CAP_DEVICE_CFG], 0, 4,
592 0, PAGE_SIZE,
593 &vdev->config_len);
594 if (!vdev->config) {
595 return STATUS_INVALID_PARAMETER;
596 }
597 }
598
599 vdev->device = &virtio_pci_device_ops;
600
601 return STATUS_SUCCESS;
602 }
603