1*823fdb19SAdam Słaboń /*
2*823fdb19SAdam Słaboń  * Virtio PCI driver - legacy (virtio 0.9) device support
3*823fdb19SAdam Słaboń  *
4*823fdb19SAdam Słaboń  * Copyright IBM Corp. 2007
5*823fdb19SAdam Słaboń  *
6*823fdb19SAdam Słaboń  * Authors:
7*823fdb19SAdam Słaboń  *  Anthony Liguori  <aliguori@us.ibm.com>
8*823fdb19SAdam Słaboń  *  Windows porting - Yan Vugenfirer <yvugenfi@redhat.com>
9*823fdb19SAdam Słaboń  *
10*823fdb19SAdam Słaboń  * Redistribution and use in source and binary forms, with or without
11*823fdb19SAdam Słaboń  * modification, are permitted provided that the following conditions
12*823fdb19SAdam Słaboń  * are met :
13*823fdb19SAdam Słaboń  * 1. Redistributions of source code must retain the above copyright
14*823fdb19SAdam Słaboń  *    notice, this list of conditions and the following disclaimer.
15*823fdb19SAdam Słaboń  * 2. Redistributions in binary form must reproduce the above copyright
16*823fdb19SAdam Słaboń  *    notice, this list of conditions and the following disclaimer in the
17*823fdb19SAdam Słaboń  *    documentation and / or other materials provided with the distribution.
18*823fdb19SAdam Słaboń  * 3. Neither the names of the copyright holders nor the names of their contributors
19*823fdb19SAdam Słaboń  *    may be used to endorse or promote products derived from this software
20*823fdb19SAdam Słaboń  *    without specific prior written permission.
21*823fdb19SAdam Słaboń  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
22*823fdb19SAdam Słaboń  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*823fdb19SAdam Słaboń  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*823fdb19SAdam Słaboń  * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
25*823fdb19SAdam Słaboń  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*823fdb19SAdam Słaboń  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*823fdb19SAdam Słaboń  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*823fdb19SAdam Słaboń  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*823fdb19SAdam Słaboń  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*823fdb19SAdam Słaboń  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*823fdb19SAdam Słaboń  * SUCH DAMAGE.
32*823fdb19SAdam Słaboń  */
33*823fdb19SAdam Słaboń #include "osdep.h"
34*823fdb19SAdam Słaboń #include "virtio_pci.h"
35*823fdb19SAdam Słaboń #include "VirtIO.h"
36*823fdb19SAdam Słaboń #include "kdebugprint.h"
37*823fdb19SAdam Słaboń #include "virtio_ring.h"
38*823fdb19SAdam Słaboń #include "virtio_pci_common.h"
39*823fdb19SAdam Słaboń #include "windows/virtio_ring_allocation.h"
40*823fdb19SAdam Słaboń 
41*823fdb19SAdam Słaboń #ifdef WPP_EVENT_TRACING
42*823fdb19SAdam Słaboń #include "VirtIOPCILegacy.tmh"
43*823fdb19SAdam Słaboń #endif
44*823fdb19SAdam Słaboń 
45*823fdb19SAdam Słaboń /////////////////////////////////////////////////////////////////////////////////////
46*823fdb19SAdam Słaboń //
47*823fdb19SAdam Słaboń // vio_legacy_dump_registers - Dump HW registers of the device
48*823fdb19SAdam Słaboń //
49*823fdb19SAdam Słaboń /////////////////////////////////////////////////////////////////////////////////////
vio_legacy_dump_registers(VirtIODevice * vdev)50*823fdb19SAdam Słaboń void vio_legacy_dump_registers(VirtIODevice *vdev)
51*823fdb19SAdam Słaboń {
52*823fdb19SAdam Słaboń     DPrintf(5, "%s\n", __FUNCTION__);
53*823fdb19SAdam Słaboń 
54*823fdb19SAdam Słaboń     DPrintf(0, "[VIRTIO_PCI_HOST_FEATURES] = %x\n", ioread32(vdev, vdev->addr + VIRTIO_PCI_HOST_FEATURES));
55*823fdb19SAdam Słaboń     DPrintf(0, "[VIRTIO_PCI_GUEST_FEATURES] = %x\n", ioread32(vdev, vdev->addr + VIRTIO_PCI_GUEST_FEATURES));
56*823fdb19SAdam Słaboń     DPrintf(0, "[VIRTIO_PCI_QUEUE_PFN] = %x\n", ioread32(vdev, vdev->addr + VIRTIO_PCI_QUEUE_PFN));
57*823fdb19SAdam Słaboń     DPrintf(0, "[VIRTIO_PCI_QUEUE_NUM] = %x\n", ioread32(vdev, vdev->addr + VIRTIO_PCI_QUEUE_NUM));
58*823fdb19SAdam Słaboń     DPrintf(0, "[VIRTIO_PCI_QUEUE_SEL] = %x\n", ioread32(vdev, vdev->addr + VIRTIO_PCI_QUEUE_SEL));
59*823fdb19SAdam Słaboń     DPrintf(0, "[VIRTIO_PCI_QUEUE_NOTIFY] = %x\n", ioread32(vdev, vdev->addr + VIRTIO_PCI_QUEUE_NOTIFY));
60*823fdb19SAdam Słaboń     DPrintf(0, "[VIRTIO_PCI_STATUS] = %x\n", ioread32(vdev, vdev->addr + VIRTIO_PCI_STATUS));
61*823fdb19SAdam Słaboń     DPrintf(0, "[VIRTIO_PCI_ISR] = %x\n", ioread32(vdev, vdev->addr + VIRTIO_PCI_ISR));
62*823fdb19SAdam Słaboń }
63*823fdb19SAdam Słaboń 
vio_legacy_get_config(VirtIODevice * vdev,unsigned offset,void * buf,unsigned len)64*823fdb19SAdam Słaboń static void vio_legacy_get_config(VirtIODevice * vdev,
65*823fdb19SAdam Słaboń                                   unsigned offset,
66*823fdb19SAdam Słaboń                                   void *buf,
67*823fdb19SAdam Słaboń                                   unsigned len)
68*823fdb19SAdam Słaboń {
69*823fdb19SAdam Słaboń     ULONG_PTR ioaddr = vdev->addr + VIRTIO_PCI_CONFIG(vdev->msix_used) + offset;
70*823fdb19SAdam Słaboń     u8 *ptr = buf;
71*823fdb19SAdam Słaboń     unsigned i;
72*823fdb19SAdam Słaboń 
73*823fdb19SAdam Słaboń     DPrintf(5, "%s\n", __FUNCTION__);
74*823fdb19SAdam Słaboń 
75*823fdb19SAdam Słaboń     for (i = 0; i < len; i++) {
76*823fdb19SAdam Słaboń         ptr[i] = ioread8(vdev, ioaddr + i);
77*823fdb19SAdam Słaboń     }
78*823fdb19SAdam Słaboń }
79*823fdb19SAdam Słaboń 
vio_legacy_set_config(VirtIODevice * vdev,unsigned offset,const void * buf,unsigned len)80*823fdb19SAdam Słaboń static void vio_legacy_set_config(VirtIODevice *vdev,
81*823fdb19SAdam Słaboń                                   unsigned offset,
82*823fdb19SAdam Słaboń                                   const void *buf,
83*823fdb19SAdam Słaboń                                   unsigned len)
84*823fdb19SAdam Słaboń {
85*823fdb19SAdam Słaboń     ULONG_PTR ioaddr = vdev->addr + VIRTIO_PCI_CONFIG(vdev->msix_used) + offset;
86*823fdb19SAdam Słaboń     const u8 *ptr = buf;
87*823fdb19SAdam Słaboń     unsigned i;
88*823fdb19SAdam Słaboń 
89*823fdb19SAdam Słaboń     DPrintf(5, "%s\n", __FUNCTION__);
90*823fdb19SAdam Słaboń 
91*823fdb19SAdam Słaboń     for (i = 0; i < len; i++) {
92*823fdb19SAdam Słaboń         iowrite8(vdev, ptr[i], ioaddr + i);
93*823fdb19SAdam Słaboń     }
94*823fdb19SAdam Słaboń }
95*823fdb19SAdam Słaboń 
vio_legacy_get_status(VirtIODevice * vdev)96*823fdb19SAdam Słaboń static u8 vio_legacy_get_status(VirtIODevice *vdev)
97*823fdb19SAdam Słaboń {
98*823fdb19SAdam Słaboń     DPrintf(6, "%s\n", __FUNCTION__);
99*823fdb19SAdam Słaboń     return ioread8(vdev, vdev->addr + VIRTIO_PCI_STATUS);
100*823fdb19SAdam Słaboń }
101*823fdb19SAdam Słaboń 
vio_legacy_set_status(VirtIODevice * vdev,u8 status)102*823fdb19SAdam Słaboń static void vio_legacy_set_status(VirtIODevice *vdev, u8 status)
103*823fdb19SAdam Słaboń {
104*823fdb19SAdam Słaboń     DPrintf(6, "%s>>> %x\n", __FUNCTION__, status);
105*823fdb19SAdam Słaboń     iowrite8(vdev, status, vdev->addr + VIRTIO_PCI_STATUS);
106*823fdb19SAdam Słaboń }
107*823fdb19SAdam Słaboń 
vio_legacy_reset(VirtIODevice * vdev)108*823fdb19SAdam Słaboń static void vio_legacy_reset(VirtIODevice *vdev)
109*823fdb19SAdam Słaboń {
110*823fdb19SAdam Słaboń     /* 0 status means a reset. */
111*823fdb19SAdam Słaboń     iowrite8(vdev, 0, vdev->addr + VIRTIO_PCI_STATUS);
112*823fdb19SAdam Słaboń }
113*823fdb19SAdam Słaboń 
vio_legacy_get_features(VirtIODevice * vdev)114*823fdb19SAdam Słaboń static u64 vio_legacy_get_features(VirtIODevice *vdev)
115*823fdb19SAdam Słaboń {
116*823fdb19SAdam Słaboń     return ioread32(vdev, vdev->addr + VIRTIO_PCI_HOST_FEATURES);
117*823fdb19SAdam Słaboń }
118*823fdb19SAdam Słaboń 
vio_legacy_set_features(VirtIODevice * vdev,u64 features)119*823fdb19SAdam Słaboń static NTSTATUS vio_legacy_set_features(VirtIODevice *vdev, u64 features)
120*823fdb19SAdam Słaboń {
121*823fdb19SAdam Słaboń     /* Give virtio_ring a chance to accept features. */
122*823fdb19SAdam Słaboń     vring_transport_features(vdev, &features);
123*823fdb19SAdam Słaboń 
124*823fdb19SAdam Słaboń     /* Make sure we don't have any features > 32 bits! */
125*823fdb19SAdam Słaboń     ASSERT((u32)features == features);
126*823fdb19SAdam Słaboń     iowrite32(vdev, (u32)features, vdev->addr + VIRTIO_PCI_GUEST_FEATURES);
127*823fdb19SAdam Słaboń 
128*823fdb19SAdam Słaboń     return STATUS_SUCCESS;
129*823fdb19SAdam Słaboń }
130*823fdb19SAdam Słaboń 
vio_legacy_set_config_vector(VirtIODevice * vdev,u16 vector)131*823fdb19SAdam Słaboń static u16 vio_legacy_set_config_vector(VirtIODevice *vdev, u16 vector)
132*823fdb19SAdam Słaboń {
133*823fdb19SAdam Słaboń     /* Setup the vector used for configuration events */
134*823fdb19SAdam Słaboń     iowrite16(vdev, vector, vdev->addr + VIRTIO_MSI_CONFIG_VECTOR);
135*823fdb19SAdam Słaboń     /* Verify we had enough resources to assign the vector */
136*823fdb19SAdam Słaboń     /* Will also flush the write out to device */
137*823fdb19SAdam Słaboń     return ioread16(vdev, vdev->addr + VIRTIO_MSI_CONFIG_VECTOR);
138*823fdb19SAdam Słaboń }
139*823fdb19SAdam Słaboń 
vio_legacy_set_queue_vector(struct virtqueue * vq,u16 vector)140*823fdb19SAdam Słaboń static u16 vio_legacy_set_queue_vector(struct virtqueue *vq, u16 vector)
141*823fdb19SAdam Słaboń {
142*823fdb19SAdam Słaboń     VirtIODevice *vdev = vq->vdev;
143*823fdb19SAdam Słaboń 
144*823fdb19SAdam Słaboń     iowrite16(vdev, (u16)vq->index, vdev->addr + VIRTIO_PCI_QUEUE_SEL);
145*823fdb19SAdam Słaboń     iowrite16(vdev, vector, vdev->addr + VIRTIO_MSI_QUEUE_VECTOR);
146*823fdb19SAdam Słaboń     return ioread16(vdev, vdev->addr + VIRTIO_MSI_QUEUE_VECTOR);
147*823fdb19SAdam Słaboń }
148*823fdb19SAdam Słaboń 
vio_legacy_query_vq_alloc(VirtIODevice * vdev,unsigned index,unsigned short * pNumEntries,unsigned long * pRingSize,unsigned long * pHeapSize)149*823fdb19SAdam Słaboń static NTSTATUS vio_legacy_query_vq_alloc(VirtIODevice *vdev,
150*823fdb19SAdam Słaboń                                           unsigned index,
151*823fdb19SAdam Słaboń                                           unsigned short *pNumEntries,
152*823fdb19SAdam Słaboń                                           unsigned long *pRingSize,
153*823fdb19SAdam Słaboń                                           unsigned long *pHeapSize)
154*823fdb19SAdam Słaboń {
155*823fdb19SAdam Słaboń     unsigned long ring_size, data_size;
156*823fdb19SAdam Słaboń     u16 num;
157*823fdb19SAdam Słaboń 
158*823fdb19SAdam Słaboń     /* Select the queue we're interested in */
159*823fdb19SAdam Słaboń     iowrite16(vdev, (u16)index, vdev->addr + VIRTIO_PCI_QUEUE_SEL);
160*823fdb19SAdam Słaboń 
161*823fdb19SAdam Słaboń     /* Check if queue is either not available or already active. */
162*823fdb19SAdam Słaboń     num = ioread16(vdev, vdev->addr + VIRTIO_PCI_QUEUE_NUM);
163*823fdb19SAdam Słaboń     if (!num || ioread32(vdev, vdev->addr + VIRTIO_PCI_QUEUE_PFN)) {
164*823fdb19SAdam Słaboń         return STATUS_NOT_FOUND;
165*823fdb19SAdam Słaboń     }
166*823fdb19SAdam Słaboń 
167*823fdb19SAdam Słaboń     ring_size = ROUND_TO_PAGES(vring_size(num, VIRTIO_PCI_VRING_ALIGN, false));
168*823fdb19SAdam Słaboń     data_size = ROUND_TO_PAGES(vring_control_block_size(num, false));
169*823fdb19SAdam Słaboń 
170*823fdb19SAdam Słaboń     *pNumEntries = num;
171*823fdb19SAdam Słaboń     *pRingSize = ring_size + data_size;
172*823fdb19SAdam Słaboń     *pHeapSize = 0;
173*823fdb19SAdam Słaboń 
174*823fdb19SAdam Słaboń     return STATUS_SUCCESS;
175*823fdb19SAdam Słaboń }
176*823fdb19SAdam Słaboń 
vio_legacy_setup_vq(struct virtqueue ** queue,VirtIODevice * vdev,VirtIOQueueInfo * info,unsigned index,u16 msix_vec)177*823fdb19SAdam Słaboń static NTSTATUS vio_legacy_setup_vq(struct virtqueue **queue,
178*823fdb19SAdam Słaboń                                     VirtIODevice *vdev,
179*823fdb19SAdam Słaboń                                     VirtIOQueueInfo *info,
180*823fdb19SAdam Słaboń                                     unsigned index,
181*823fdb19SAdam Słaboń                                     u16 msix_vec)
182*823fdb19SAdam Słaboń {
183*823fdb19SAdam Słaboń     struct virtqueue *vq;
184*823fdb19SAdam Słaboń     unsigned long ring_size, heap_size;
185*823fdb19SAdam Słaboń     NTSTATUS status;
186*823fdb19SAdam Słaboń 
187*823fdb19SAdam Słaboń     /* Select the queue and query allocation parameters */
188*823fdb19SAdam Słaboń     status = vio_legacy_query_vq_alloc(vdev, index, &info->num, &ring_size, &heap_size);
189*823fdb19SAdam Słaboń     if (!NT_SUCCESS(status)) {
190*823fdb19SAdam Słaboń         return status;
191*823fdb19SAdam Słaboń     }
192*823fdb19SAdam Słaboń 
193*823fdb19SAdam Słaboń     info->queue = mem_alloc_contiguous_pages(vdev, ring_size);
194*823fdb19SAdam Słaboń     if (info->queue == NULL) {
195*823fdb19SAdam Słaboń         return STATUS_INSUFFICIENT_RESOURCES;
196*823fdb19SAdam Słaboń     }
197*823fdb19SAdam Słaboń 
198*823fdb19SAdam Słaboń     /* activate the queue */
199*823fdb19SAdam Słaboń     iowrite32(vdev, (u32)(mem_get_physical_address(vdev, info->queue) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT),
200*823fdb19SAdam Słaboń         vdev->addr + VIRTIO_PCI_QUEUE_PFN);
201*823fdb19SAdam Słaboń 
202*823fdb19SAdam Słaboń     /* create the vring */
203*823fdb19SAdam Słaboń     vq = vring_new_virtqueue_split(index, info->num,
204*823fdb19SAdam Słaboń         VIRTIO_PCI_VRING_ALIGN, vdev,
205*823fdb19SAdam Słaboń         info->queue, vp_notify,
206*823fdb19SAdam Słaboń         (u8 *)info->queue + ROUND_TO_PAGES(vring_size(info->num, VIRTIO_PCI_VRING_ALIGN, false)));
207*823fdb19SAdam Słaboń     if (!vq) {
208*823fdb19SAdam Słaboń         status = STATUS_INSUFFICIENT_RESOURCES;
209*823fdb19SAdam Słaboń         goto err_activate_queue;
210*823fdb19SAdam Słaboń     }
211*823fdb19SAdam Słaboń 
212*823fdb19SAdam Słaboń     vq->notification_addr = (void *)(vdev->addr + VIRTIO_PCI_QUEUE_NOTIFY);
213*823fdb19SAdam Słaboń 
214*823fdb19SAdam Słaboń     if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
215*823fdb19SAdam Słaboń         msix_vec = vdev->device->set_queue_vector(vq, msix_vec);
216*823fdb19SAdam Słaboń         if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
217*823fdb19SAdam Słaboń             status = STATUS_DEVICE_BUSY;
218*823fdb19SAdam Słaboń             goto err_assign;
219*823fdb19SAdam Słaboń         }
220*823fdb19SAdam Słaboń     }
221*823fdb19SAdam Słaboń 
222*823fdb19SAdam Słaboń     *queue = vq;
223*823fdb19SAdam Słaboń     return STATUS_SUCCESS;
224*823fdb19SAdam Słaboń 
225*823fdb19SAdam Słaboń err_assign:
226*823fdb19SAdam Słaboń err_activate_queue:
227*823fdb19SAdam Słaboń     iowrite32(vdev, 0, vdev->addr + VIRTIO_PCI_QUEUE_PFN);
228*823fdb19SAdam Słaboń     mem_free_contiguous_pages(vdev, info->queue);
229*823fdb19SAdam Słaboń     return status;
230*823fdb19SAdam Słaboń }
231*823fdb19SAdam Słaboń 
vio_legacy_del_vq(VirtIOQueueInfo * info)232*823fdb19SAdam Słaboń static void vio_legacy_del_vq(VirtIOQueueInfo *info)
233*823fdb19SAdam Słaboń {
234*823fdb19SAdam Słaboń     struct virtqueue *vq = info->vq;
235*823fdb19SAdam Słaboń     VirtIODevice *vdev = vq->vdev;
236*823fdb19SAdam Słaboń 
237*823fdb19SAdam Słaboń     iowrite16(vdev, (u16)vq->index, vdev->addr + VIRTIO_PCI_QUEUE_SEL);
238*823fdb19SAdam Słaboń 
239*823fdb19SAdam Słaboń     if (vdev->msix_used) {
240*823fdb19SAdam Słaboń         iowrite16(vdev, VIRTIO_MSI_NO_VECTOR,
241*823fdb19SAdam Słaboń             vdev->addr + VIRTIO_MSI_QUEUE_VECTOR);
242*823fdb19SAdam Słaboń         /* Flush the write out to device */
243*823fdb19SAdam Słaboń         ioread8(vdev, vdev->addr + VIRTIO_PCI_ISR);
244*823fdb19SAdam Słaboń     }
245*823fdb19SAdam Słaboń 
246*823fdb19SAdam Słaboń     /* Select and deactivate the queue */
247*823fdb19SAdam Słaboń     iowrite32(vdev, 0, vdev->addr + VIRTIO_PCI_QUEUE_PFN);
248*823fdb19SAdam Słaboń 
249*823fdb19SAdam Słaboń     mem_free_contiguous_pages(vdev, info->queue);
250*823fdb19SAdam Słaboń }
251*823fdb19SAdam Słaboń 
252*823fdb19SAdam Słaboń static const struct virtio_device_ops virtio_pci_device_ops = {
253*823fdb19SAdam Słaboń     /* .get_config = */ vio_legacy_get_config,
254*823fdb19SAdam Słaboń     /* .set_config = */ vio_legacy_set_config,
255*823fdb19SAdam Słaboń     /* .get_config_generation = */ NULL,
256*823fdb19SAdam Słaboń     /* .get_status = */ vio_legacy_get_status,
257*823fdb19SAdam Słaboń     /* .set_status = */ vio_legacy_set_status,
258*823fdb19SAdam Słaboń     /* .reset = */ vio_legacy_reset,
259*823fdb19SAdam Słaboń     /* .get_features = */ vio_legacy_get_features,
260*823fdb19SAdam Słaboń     /* .set_features = */ vio_legacy_set_features,
261*823fdb19SAdam Słaboń     /* .set_config_vector = */ vio_legacy_set_config_vector,
262*823fdb19SAdam Słaboń     /* .set_queue_vector = */ vio_legacy_set_queue_vector,
263*823fdb19SAdam Słaboń     /* .query_queue_alloc = */ vio_legacy_query_vq_alloc,
264*823fdb19SAdam Słaboń     /* .setup_queue = */ vio_legacy_setup_vq,
265*823fdb19SAdam Słaboń     /* .delete_queue = */ vio_legacy_del_vq,
266*823fdb19SAdam Słaboń };
267*823fdb19SAdam Słaboń 
268*823fdb19SAdam Słaboń /* Legacy device initialization */
vio_legacy_initialize(VirtIODevice * vdev)269*823fdb19SAdam Słaboń NTSTATUS vio_legacy_initialize(VirtIODevice *vdev)
270*823fdb19SAdam Słaboń {
271*823fdb19SAdam Słaboń     size_t length = pci_get_resource_len(vdev, 0);
272*823fdb19SAdam Słaboń     vdev->addr = (ULONG_PTR)pci_map_address_range(vdev, 0, 0, length);
273*823fdb19SAdam Słaboń 
274*823fdb19SAdam Słaboń     if (!vdev->addr) {
275*823fdb19SAdam Słaboń         return STATUS_INSUFFICIENT_RESOURCES;
276*823fdb19SAdam Słaboń     }
277*823fdb19SAdam Słaboń 
278*823fdb19SAdam Słaboń     vdev->isr = (u8 *)vdev->addr + VIRTIO_PCI_ISR;
279*823fdb19SAdam Słaboń 
280*823fdb19SAdam Słaboń     vdev->device = &virtio_pci_device_ops;
281*823fdb19SAdam Słaboń 
282*823fdb19SAdam Słaboń     return STATUS_SUCCESS;
283*823fdb19SAdam Słaboń }
284