ReactOS 0.4.16-dev-303-g11d5cb8
VirtIOPCICommon.c
Go to the documentation of this file.
1/*
2 * Virtio PCI driver - common functionality for all device versions
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
36#include "osdep.h"
37#include "virtio_pci.h"
38#include "VirtIO.h"
39#include "kdebugprint.h"
40#include <stddef.h>
41
42#include "virtio_pci_common.h"
43
45 const VirtIOSystemOps *pSystemOps,
47 bool msix_used)
48{
50
51 RtlZeroMemory(vdev, sizeof(VirtIODevice));
53 vdev->system = pSystemOps;
54 vdev->msix_used = msix_used;
55 vdev->info = vdev->inline_info;
56 vdev->maxQueues = ARRAYSIZE(vdev->inline_info);
57
60 /* fall back to legacy virtio device */
62 }
63 if (NT_SUCCESS(status)) {
64 /* Always start by resetting the device */
66
67 /* Acknowledge that we've seen the device. */
69
70 /* If we are here, we must have found a driver for the device */
72 }
73
74 return status;
75}
76
78{
79 if (vdev->info &&
80 vdev->info != vdev->inline_info) {
81 mem_free_nonpaged_block(vdev, vdev->info);
82 vdev->info = NULL;
83 }
84}
85
87{
88 return vdev->device->get_status(vdev);
89}
90
92{
93 vdev->device->set_status(vdev, status);
94}
95
97{
98 vdev->device->set_status(vdev, (u8)(vdev->device->get_status(vdev) | status));
99}
100
102{
103 vdev->device->reset(vdev);
104}
105
107{
108 unsigned status = vdev->device->get_status(vdev);
109
111 vdev->device->set_status(vdev, (u8)(status | VIRTIO_CONFIG_S_DRIVER_OK));
112}
113
115{
116 return vdev->device->get_features(vdev);
117}
118
120{
121 unsigned char dev_status;
123
126
127 status = vdev->device->set_features(vdev, features);
128 if (!NT_SUCCESS(status)) {
129 return status;
130 }
131
133 return status;
134 }
135
137 dev_status = vdev->device->get_status(vdev);
138 if (!(dev_status & VIRTIO_CONFIG_S_FEATURES_OK)) {
139 DPrintf(0, "virtio: device refuses features: %x\n", dev_status);
141 }
142 return status;
143}
144
145/* Read @count fields, @bytes each. */
147 unsigned int offset,
148 void *buf, size_t count, size_t bytes)
149{
150 u32 old, gen = vdev->device->get_config_generation ?
151 vdev->device->get_config_generation(vdev) : 0;
152 size_t i;
153
154 do {
155 old = gen;
156
157 for (i = 0; i < count; i++) {
158 vdev->device->get_config(vdev, (unsigned)(offset + bytes * i),
159 (char *)buf + i * bytes, (unsigned)bytes);
160 }
161
162 gen = vdev->device->get_config_generation ?
163 vdev->device->get_config_generation(vdev) : 0;
164 } while (gen != old);
165}
166
168 void *buf, unsigned len)
169{
170 switch (len) {
171 case 1:
172 case 2:
173 case 4:
174 vdev->device->get_config(vdev, offset, buf, len);
175 break;
176 case 8:
177 virtio_cread_many(vdev, offset, buf, 2, sizeof(u32));
178 break;
179 default:
180 virtio_cread_many(vdev, offset, buf, len, 1);
181 break;
182 }
183}
184
185/* Write @count fields, @bytes each. */
187 unsigned int offset,
188 void *buf, size_t count, size_t bytes)
189{
190 size_t i;
191 for (i = 0; i < count; i++) {
192 vdev->device->set_config(vdev, (unsigned)(offset + bytes * i),
193 (char *)buf + i * bytes, (unsigned)bytes);
194 }
195}
196
198 void *buf, unsigned len)
199{
200 switch (len) {
201 case 1:
202 case 2:
203 case 4:
204 vdev->device->set_config(vdev, offset, buf, len);
205 break;
206 case 8:
207 virtio_cwrite_many(vdev, offset, buf, 2, sizeof(u32));
208 break;
209 default:
210 virtio_cwrite_many(vdev, offset, buf, len, 1);
211 break;
212 }
213}
214
216 unsigned index,
217 unsigned short *pNumEntries,
218 unsigned long *pRingSize,
219 unsigned long *pHeapSize)
220{
221 return vdev->device->query_queue_alloc(vdev, index, pNumEntries, pRingSize, pHeapSize);
222}
223
225{
226 if (nvqs > vdev->maxQueues) {
227 /* allocate new space for queue infos */
228 void *new_info = mem_alloc_nonpaged_block(vdev, nvqs * virtio_get_queue_descriptor_size());
229 if (!new_info) {
231 }
232
233 if (vdev->info && vdev->info != vdev->inline_info) {
234 mem_free_nonpaged_block(vdev, vdev->info);
235 }
236 vdev->info = new_info;
237 vdev->maxQueues = nvqs;
238 }
239 return STATUS_SUCCESS;
240}
241
243 VirtIODevice *vdev, unsigned index,
244 u16 msix_vec)
245{
246 VirtIOQueueInfo *info = &vdev->info[index];
247
248 NTSTATUS status = vdev->device->setup_queue(queue, vdev, info, index, msix_vec);
249 if (NT_SUCCESS(status)) {
250 info->vq = *queue;
251 }
252
253 return status;
254}
255
257 struct virtqueue **vq)
258{
259 u16 msix_vec = vdev_get_msix_vector(vdev, index);
260 return vp_setup_vq(
261 vq,
262 vdev,
263 index,
264 msix_vec);
265}
266
268 unsigned nvqs,
269 struct virtqueue *vqs[])
270{
271 unsigned i;
273 u16 msix_vec;
274
276 if (!NT_SUCCESS(status)) {
277 return status;
278 }
279
280 /* set up the device config interrupt */
281 msix_vec = vdev_get_msix_vector(vdev, -1);
282
283 if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
284 msix_vec = vdev->device->set_config_vector(vdev, msix_vec);
285 /* Verify we had enough resources to assign the vector */
286 if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
288 goto error_find;
289 }
290 }
291
292 /* set up queue interrupts */
293 for (i = 0; i < nvqs; i++) {
294 msix_vec = vdev_get_msix_vector(vdev, i);
296 &vqs[i],
297 vdev,
298 i,
299 msix_vec);
300 if (!NT_SUCCESS(status)) {
301 goto error_find;
302 }
303 }
304 return STATUS_SUCCESS;
305
306error_find:
308 return status;
309}
310
312{
313 VirtIODevice *vdev = vq->vdev;
314 unsigned i = vq->index;
315
316 vdev->device->delete_queue(&vdev->info[i]);
317 vdev->info[i].vq = NULL;
318}
319
321{
322 struct virtqueue *vq;
323 unsigned i;
324
325 if (vdev->info == NULL)
326 return;
327
328 for (i = 0; i < vdev->maxQueues; i++) {
329 vq = vdev->info[i].vq;
330 if (vq != NULL) {
331 vdev->device->delete_queue(&vdev->info[i]);
332 vdev->info[i].vq = NULL;
333 }
334 }
335}
336
338{
339 return vq->vdev->info[vq->index].num;
340}
341
343{
344 return vdev->device->set_config_vector(vdev, vector);
345}
346
348{
349 return vq->vdev->device->set_queue_vector(vq, vector);
350}
351
353{
354 return ioread8(vdev, vdev->isr);
355}
356
358{
359 int iBar, i;
360
361 /* no point in supporting PCI and CardBus bridges */
362 ASSERT((pPCIHeader->HeaderType & ~PCI_MULTIFUNCTION) == PCI_DEVICE_TYPE);
363
364 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) {
366 BAR.LowPart = pPCIHeader->u.type0.BaseAddresses[i];
367
368 iBar = i;
369 if (BAR.LowPart & PCI_ADDRESS_IO_SPACE) {
370 /* I/O space */
372 BAR.HighPart = 0;
374 /* memory space 64-bit */
376 BAR.HighPart = pPCIHeader->u.type0.BaseAddresses[++i];
377 } else {
378 /* memory space 32-bit */
380 BAR.HighPart = 0;
381 }
382
383 if (BAR.QuadPart == BasePA.QuadPart) {
384 return iBar;
385 }
386 }
387 return -1;
388}
389
390/* The notify function used when creating a virt queue, common to both modern
391 * and legacy (the difference is in how vq->notification_addr is set up).
392 */
393void vp_notify(struct virtqueue *vq)
394{
395 /* we write the queue's selector into the notification register to
396 * signal the other end */
397 iowrite16(vq->vdev, (unsigned short)vq->index, vq->notification_addr);
398 DPrintf(6, "virtio: vp_notify vq->index = %x\n", vq->index);
399}
400
402{
403 vq->notification_cb(vq);
404}
405
406void virtqueue_kick(struct virtqueue *vq)
407{
408 if (virtqueue_kick_prepare(vq)) {
410 }
411}
int virtio_get_bar_index(PPCI_COMMON_HEADER pPCIHeader, PHYSICAL_ADDRESS BasePA)
NTSTATUS virtio_device_initialize(VirtIODevice *vdev, const VirtIOSystemOps *pSystemOps, PVOID DeviceContext, bool msix_used)
static NTSTATUS vp_setup_vq(struct virtqueue **queue, VirtIODevice *vdev, unsigned index, u16 msix_vec)
u32 virtio_get_queue_size(struct virtqueue *vq)
NTSTATUS virtio_find_queues(VirtIODevice *vdev, unsigned nvqs, struct virtqueue *vqs[])
void virtio_device_shutdown(VirtIODevice *vdev)
u16 virtio_set_queue_vector(struct virtqueue *vq, u16 vector)
void virtqueue_kick(struct virtqueue *vq)
void virtio_delete_queues(VirtIODevice *vdev)
void virtio_set_status(VirtIODevice *vdev, u8 status)
void virtio_add_status(VirtIODevice *vdev, u8 status)
void virtqueue_notify(struct virtqueue *vq)
void virtio_device_ready(VirtIODevice *vdev)
void virtio_set_config(VirtIODevice *vdev, unsigned offset, void *buf, unsigned len)
NTSTATUS virtio_find_queue(VirtIODevice *vdev, unsigned index, struct virtqueue **vq)
NTSTATUS virtio_reserve_queue_memory(VirtIODevice *vdev, unsigned nvqs)
static void virtio_cwrite_many(VirtIODevice *vdev, unsigned int offset, void *buf, size_t count, size_t bytes)
u8 virtio_read_isr_status(VirtIODevice *vdev)
u8 virtio_get_status(VirtIODevice *vdev)
void vp_notify(struct virtqueue *vq)
void virtio_delete_queue(struct virtqueue *vq)
void virtio_device_reset(VirtIODevice *vdev)
static void virtio_cread_many(VirtIODevice *vdev, unsigned int offset, void *buf, size_t count, size_t bytes)
NTSTATUS virtio_query_queue_allocation(VirtIODevice *vdev, unsigned index, unsigned short *pNumEntries, unsigned long *pRingSize, unsigned long *pHeapSize)
u64 virtio_get_features(VirtIODevice *vdev)
void virtio_get_config(VirtIODevice *vdev, unsigned offset, void *buf, unsigned len)
u16 virtio_set_config_vector(VirtIODevice *vdev, u16 vector)
NTSTATUS virtio_set_features(VirtIODevice *vdev, u64 features)
static bool virtqueue_kick_prepare(struct virtqueue *vq)
Definition: VirtIO.h:75
static unsigned char bytes[4]
Definition: adnsresfilter.c:74
LONG NTSTATUS
Definition: precomp.h:26
#define index(s, c)
Definition: various.h:29
ULONG32 u32
Definition: btrfs.h:14
ULONG64 u64
Definition: btrfs.h:15
UCHAR u8
Definition: btrfs.h:12
USHORT u16
Definition: btrfs.h:13
Definition: _queue.h:67
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define DPrintf(Level, Fmt)
Definition: kdebugprint.h:61
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint index
Definition: glext.h:6031
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLsizei len
Definition: glext.h:6722
GLintptr offset
Definition: glext.h:5920
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ASSERT(a)
Definition: mode.c:44
_In_ PNDIS_STRING _In_opt_ NDIS_HANDLE DeviceContext
Definition: ndis.h:5246
#define STATUS_SUCCESS
Definition: shellext.h:65
Definition: ps.c:97
ULONG maxQueues
Definition: virtio_pci.h:273
bool event_suppression_enabled
Definition: virtio_pci.h:245
volatile u8 * isr
Definition: virtio_pci.h:260
VirtIOQueueInfo * info
Definition: virtio_pci.h:277
const struct virtio_system_ops * system
Definition: virtio_pci.h:254
const struct virtio_device_ops * device
Definition: virtio_pci.h:251
void * DeviceContext
Definition: virtio_pci.h:257
VirtIOQueueInfo inline_info[MAX_QUEUES_PER_DEVICE_DEFAULT]
Definition: virtio_pci.h:278
bool packed_ring
Definition: virtio_pci.h:248
struct virtqueue * vq
Definition: virtio_pci.h:161
void * notification_addr
Definition: VirtIO.h:47
unsigned int index
Definition: VirtIO.h:45
void(* notification_cb)(struct virtqueue *vq)
Definition: VirtIO.h:46
VirtIODevice * vdev
Definition: VirtIO.h:44
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define STATUS_DEVICE_NOT_CONNECTED
Definition: udferr_usr.h:160
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_DEVICE_BUSY
Definition: udferr_usr.h:129
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
#define VIRTIO_CONFIG_S_DRIVER
Definition: virtio_config.h:37
#define VIRTIO_F_RING_PACKED
Definition: virtio_config.h:68
#define VIRTIO_CONFIG_S_FEATURES_OK
Definition: virtio_config.h:41
#define VIRTIO_CONFIG_S_ACKNOWLEDGE
Definition: virtio_config.h:35
#define VIRTIO_F_VERSION_1
Definition: virtio_config.h:63
#define VIRTIO_CONFIG_S_DRIVER_OK
Definition: virtio_config.h:39
#define virtio_is_feature_enabled(FeaturesList, Feature)
Definition: virtio_pci.h:311
#define VIRTIO_MSI_NO_VECTOR
Definition: virtio_pci.h:98
static ULONG FORCEINLINE virtio_get_queue_descriptor_size()
Definition: virtio_pci.h:366
#define mem_free_nonpaged_block(vdev, addr)
#define mem_alloc_nonpaged_block(vdev, size)
NTSTATUS vio_modern_initialize(VirtIODevice *vdev)
#define iowrite16(vdev, val, addr)
#define ioread8(vdev, addr)
NTSTATUS vio_legacy_initialize(VirtIODevice *vdev)
#define vdev_get_msix_vector(vdev, queue)
#define VIRTIO_RING_F_EVENT_IDX
Definition: virtio_ring.h:45
#define PCI_TYPE_64BIT
Definition: iotypes.h:4239
#define PCI_MULTIFUNCTION
Definition: iotypes.h:3604
#define PCI_ADDRESS_IO_ADDRESS_MASK
Definition: iotypes.h:4233
#define PCI_TYPE0_ADDRESSES
Definition: iotypes.h:3500
#define PCI_ADDRESS_IO_SPACE
Definition: iotypes.h:4230
#define PCI_ADDRESS_MEMORY_ADDRESS_MASK
Definition: iotypes.h:4234
#define PCI_ADDRESS_MEMORY_TYPE_MASK
Definition: iotypes.h:4231
#define PCI_DEVICE_TYPE
Definition: iotypes.h:3605