]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/VirtioLib/VirtioLib.c
OvmfPkg: Make the VirtIo devices use the new VIRTIO_DEVICE_PROTOCOL
[mirror_edk2.git] / OvmfPkg / Library / VirtioLib / VirtioLib.c
1 /** @file
2
3 Utility functions used by virtio device drivers.
4
5 Copyright (C) 2012, Red Hat, Inc.
6 Portion of Copyright (C) 2013, ARM Ltd.
7
8 This program and the accompanying materials are licensed and made available
9 under the terms and conditions of the BSD License which accompanies this
10 distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include <Library/BaseLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23
24 #include <Library/VirtioLib.h>
25
26
27 /**
28
29 Write a word into Region 0 of the device specified by VirtIo.
30
31 Region 0 must be an iomem region. This is an internal function for the
32 driver-specific VIRTIO_CFG_WRITE() macros.
33
34 @param[in] VirtIo Target VirtIo device.
35
36 @param[in] FieldOffset Destination offset.
37
38 @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.
39
40 @param[in] Value Little endian value to write, converted to UINT64.
41 The least significant FieldSize bytes will be used.
42
43
44 @return Status code returned by VirtIo->Io.Write().
45
46 **/
47 EFI_STATUS
48 EFIAPI
49 VirtioWriteDevice (
50 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
51 IN UINTN FieldOffset,
52 IN UINTN FieldSize,
53 IN UINT64 Value
54 )
55 {
56 return VirtIo->WriteDevice (VirtIo, FieldOffset, FieldSize, Value);
57 }
58
59
60 /**
61
62 Read a word from Region 0 of the device specified by VirtIo.
63
64 Region 0 must be an iomem region. This is an internal function for the
65 driver-specific VIRTIO_CFG_READ() macros.
66
67 @param[in] VirtIo Source VirtIo device.
68
69 @param[in] FieldOffset Source offset.
70
71 @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.
72
73 @param[in] BufferSize Number of bytes available in the target buffer. Must
74 equal FieldSize.
75
76 @param[out] Buffer Target buffer.
77
78
79 @return Status code returned by VirtIo->Io.Read().
80
81 **/
82 EFI_STATUS
83 EFIAPI
84 VirtioReadDevice (
85 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
86 IN UINTN FieldOffset,
87 IN UINTN FieldSize,
88 IN UINTN BufferSize,
89 OUT VOID *Buffer
90 )
91 {
92 return VirtIo->ReadDevice (VirtIo, FieldOffset, FieldSize, BufferSize, Buffer);
93 }
94
95
96 /**
97
98 Configure a virtio ring.
99
100 This function sets up internal storage (the guest-host communication area)
101 and lays out several "navigation" (ie. no-ownership) pointers to parts of
102 that storage.
103
104 Relevant sections from the virtio-0.9.5 spec:
105 - 1.1 Virtqueues,
106 - 2.3 Virtqueue Configuration.
107
108 @param[in] The number of descriptors to allocate for the
109 virtio ring, as requested by the host.
110
111 @param[out] Ring The virtio ring to set up.
112
113 @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous
114 pages for the requested QueueSize. Fields of
115 Ring have indeterminate value.
116
117 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base
118 (and nothing else) is responsible for
119 deallocation.
120
121 **/
122 EFI_STATUS
123 EFIAPI
124 VirtioRingInit (
125 IN UINT16 QueueSize,
126 OUT VRING *Ring
127 )
128 {
129 UINTN RingSize;
130 volatile UINT8 *RingPagesPtr;
131
132 RingSize = ALIGN_VALUE (
133 sizeof *Ring->Desc * QueueSize +
134 sizeof *Ring->Avail.Flags +
135 sizeof *Ring->Avail.Idx +
136 sizeof *Ring->Avail.Ring * QueueSize +
137 sizeof *Ring->Avail.UsedEvent,
138 EFI_PAGE_SIZE);
139
140 RingSize += ALIGN_VALUE (
141 sizeof *Ring->Used.Flags +
142 sizeof *Ring->Used.Idx +
143 sizeof *Ring->Used.UsedElem * QueueSize +
144 sizeof *Ring->Used.AvailEvent,
145 EFI_PAGE_SIZE);
146
147 Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize);
148 Ring->Base = AllocatePages (Ring->NumPages);
149 if (Ring->Base == NULL) {
150 return EFI_OUT_OF_RESOURCES;
151 }
152 SetMem (Ring->Base, RingSize, 0x00);
153 RingPagesPtr = Ring->Base;
154
155 Ring->Desc = (volatile VOID *) RingPagesPtr;
156 RingPagesPtr += sizeof *Ring->Desc * QueueSize;
157
158 Ring->Avail.Flags = (volatile VOID *) RingPagesPtr;
159 RingPagesPtr += sizeof *Ring->Avail.Flags;
160
161 Ring->Avail.Idx = (volatile VOID *) RingPagesPtr;
162 RingPagesPtr += sizeof *Ring->Avail.Idx;
163
164 Ring->Avail.Ring = (volatile VOID *) RingPagesPtr;
165 RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize;
166
167 Ring->Avail.UsedEvent = (volatile VOID *) RingPagesPtr;
168 RingPagesPtr += sizeof *Ring->Avail.UsedEvent;
169
170 RingPagesPtr = (volatile UINT8 *) Ring->Base +
171 ALIGN_VALUE (RingPagesPtr - (volatile UINT8 *) Ring->Base,
172 EFI_PAGE_SIZE);
173
174 Ring->Used.Flags = (volatile VOID *) RingPagesPtr;
175 RingPagesPtr += sizeof *Ring->Used.Flags;
176
177 Ring->Used.Idx = (volatile VOID *) RingPagesPtr;
178 RingPagesPtr += sizeof *Ring->Used.Idx;
179
180 Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;
181 RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;
182
183 Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
184 RingPagesPtr += sizeof *Ring->Used.AvailEvent;
185
186 Ring->QueueSize = QueueSize;
187 return EFI_SUCCESS;
188 }
189
190
191 /**
192
193 Tear down the internal resources of a configured virtio ring.
194
195 The caller is responsible to stop the host from using this ring before
196 invoking this function: the VSTAT_DRIVER_OK bit must be clear in
197 VhdrDeviceStatus.
198
199 @param[out] Ring The virtio ring to clean up.
200
201 **/
202 VOID
203 EFIAPI
204 VirtioRingUninit (
205 IN OUT VRING *Ring
206 )
207 {
208 FreePages (Ring->Base, Ring->NumPages);
209 SetMem (Ring, sizeof *Ring, 0x00);
210 }
211
212
213 /**
214
215 Turn off interrupt notifications from the host, and prepare for appending
216 multiple descriptors to the virtio ring.
217
218 The calling driver must be in VSTAT_DRIVER_OK state.
219
220 @param[in,out] Ring The virtio ring we intend to append descriptors to.
221
222 @param[out] Indices The DESC_INDICES structure to initialize.
223
224 **/
225 VOID
226 EFIAPI
227 VirtioPrepare (
228 IN OUT VRING *Ring,
229 OUT DESC_INDICES *Indices
230 )
231 {
232 //
233 // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.
234 // We're going to poll the answer, the host should not send an interrupt.
235 //
236 *Ring->Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;
237
238 //
239 // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.
240 //
241 // Since we support only one in-flight descriptor chain, we can always build
242 // that chain starting at entry #0 of the descriptor table.
243 //
244 Indices->HeadDescIdx = 0;
245 Indices->NextDescIdx = Indices->HeadDescIdx;
246 }
247
248
249 /**
250
251 Append a contiguous buffer for transmission / reception via the virtio ring.
252
253 This function implements the following section from virtio-0.9.5:
254 - 2.4.1.1 Placing Buffers into the Descriptor Table
255
256 Free space is taken as granted, since the individual drivers support only
257 synchronous requests and host side status is processed in lock-step with
258 request submission. It is the calling driver's responsibility to verify the
259 ring size in advance.
260
261 The caller is responsible for initializing *Indices with VirtioPrepare()
262 first.
263
264 @param[in,out] Ring The virtio ring to append the buffer to, as a
265 descriptor.
266
267 @param[in] BufferPhysAddr (Guest pseudo-physical) start address of the
268 transmit / receive buffer.
269
270 @param[in] BufferSize Number of bytes to transmit or receive.
271
272 @param[in] Flags A bitmask of VRING_DESC_F_* flags. The caller
273 computes this mask dependent on further buffers to
274 append and transfer direction.
275 VRING_DESC_F_INDIRECT is unsupported. The
276 VRING_DESC.Next field is always set, but the host
277 only interprets it dependent on VRING_DESC_F_NEXT.
278
279 @param[in,out] Indices Indices->HeadDescIdx is not accessed.
280 On input, Indices->NextDescIdx identifies the next
281 descriptor to carry the buffer. On output,
282 Indices->NextDescIdx is incremented by one, modulo
283 2^16.
284
285 **/
286 VOID
287 EFIAPI
288 VirtioAppendDesc (
289 IN OUT VRING *Ring,
290 IN UINTN BufferPhysAddr,
291 IN UINT32 BufferSize,
292 IN UINT16 Flags,
293 IN OUT DESC_INDICES *Indices
294 )
295 {
296 volatile VRING_DESC *Desc;
297
298 Desc = &Ring->Desc[Indices->NextDescIdx++ % Ring->QueueSize];
299 Desc->Addr = BufferPhysAddr;
300 Desc->Len = BufferSize;
301 Desc->Flags = Flags;
302 Desc->Next = Indices->NextDescIdx % Ring->QueueSize;
303 }
304
305
306 /**
307
308 Notify the host about the descriptor chain just built, and wait until the
309 host processes it.
310
311 @param[in] VirtIo The target virtio device to notify.
312
313 @param[in] VirtQueueId Identifies the queue for the target device.
314
315 @param[in,out] Ring The virtio ring with descriptors to submit.
316
317 @param[in] Indices Indices->NextDescIdx is not accessed.
318 Indices->HeadDescIdx identifies the head descriptor
319 of the descriptor chain.
320
321
322 @return Error code from VirtIo->SetQueueNotify() if it fails.
323
324 @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
325
326 **/
327 EFI_STATUS
328 EFIAPI
329 VirtioFlush (
330 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
331 IN UINT16 VirtQueueId,
332 IN OUT VRING *Ring,
333 IN DESC_INDICES *Indices
334 )
335 {
336 UINT16 NextAvailIdx;
337 EFI_STATUS Status;
338 UINTN PollPeriodUsecs;
339
340 //
341 // virtio-0.9.5, 2.4.1.2 Updating the Available Ring
342 //
343 // It is not exactly clear from the wording of the virtio-0.9.5
344 // specification, but each entry in the Available Ring references only the
345 // head descriptor of any given descriptor chain.
346 //
347 NextAvailIdx = *Ring->Avail.Idx;
348 Ring->Avail.Ring[NextAvailIdx++ % Ring->QueueSize] =
349 Indices->HeadDescIdx % Ring->QueueSize;
350
351 //
352 // virtio-0.9.5, 2.4.1.3 Updating the Index Field
353 //
354 MemoryFence();
355 *Ring->Avail.Idx = NextAvailIdx;
356
357 //
358 // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are
359 // OK.
360 //
361 MemoryFence();
362 Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId);
363 if (EFI_ERROR (Status)) {
364 return Status;
365 }
366
367 //
368 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
369 // Wait until the host processes and acknowledges our descriptor chain. The
370 // condition we use for polling is greatly simplified and relies on the
371 // synchronous, lock-step progress.
372 //
373 // Keep slowing down until we reach a poll period of slightly above 1 ms.
374 //
375 PollPeriodUsecs = 1;
376 MemoryFence();
377 while (*Ring->Used.Idx != NextAvailIdx) {
378 gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay
379
380 if (PollPeriodUsecs < 1024) {
381 PollPeriodUsecs *= 2;
382 }
383 MemoryFence();
384 }
385
386 MemoryFence();
387 return EFI_SUCCESS;
388 }