3 Utility functions used by virtio device drivers.
5 Copyright (C) 2012, Red Hat, Inc.
6 Portion of Copyright (C) 2013, ARM Ltd.
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
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.
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>
24 #include <Library/VirtioLib.h>
29 Configure a virtio ring.
31 This function sets up internal storage (the guest-host communication area)
32 and lays out several "navigation" (ie. no-ownership) pointers to parts of
35 Relevant sections from the virtio-0.9.5 spec:
37 - 2.3 Virtqueue Configuration.
39 @param[in] The number of descriptors to allocate for the
40 virtio ring, as requested by the host.
42 @param[out] Ring The virtio ring to set up.
44 @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous
45 pages for the requested QueueSize. Fields of
46 Ring have indeterminate value.
48 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base
49 (and nothing else) is responsible for
61 volatile UINT8
*RingPagesPtr
;
63 RingSize
= ALIGN_VALUE (
64 sizeof *Ring
->Desc
* QueueSize
+
65 sizeof *Ring
->Avail
.Flags
+
66 sizeof *Ring
->Avail
.Idx
+
67 sizeof *Ring
->Avail
.Ring
* QueueSize
+
68 sizeof *Ring
->Avail
.UsedEvent
,
71 RingSize
+= ALIGN_VALUE (
72 sizeof *Ring
->Used
.Flags
+
73 sizeof *Ring
->Used
.Idx
+
74 sizeof *Ring
->Used
.UsedElem
* QueueSize
+
75 sizeof *Ring
->Used
.AvailEvent
,
78 Ring
->NumPages
= EFI_SIZE_TO_PAGES (RingSize
);
79 Ring
->Base
= AllocatePages (Ring
->NumPages
);
80 if (Ring
->Base
== NULL
) {
81 return EFI_OUT_OF_RESOURCES
;
83 SetMem (Ring
->Base
, RingSize
, 0x00);
84 RingPagesPtr
= Ring
->Base
;
86 Ring
->Desc
= (volatile VOID
*) RingPagesPtr
;
87 RingPagesPtr
+= sizeof *Ring
->Desc
* QueueSize
;
89 Ring
->Avail
.Flags
= (volatile VOID
*) RingPagesPtr
;
90 RingPagesPtr
+= sizeof *Ring
->Avail
.Flags
;
92 Ring
->Avail
.Idx
= (volatile VOID
*) RingPagesPtr
;
93 RingPagesPtr
+= sizeof *Ring
->Avail
.Idx
;
95 Ring
->Avail
.Ring
= (volatile VOID
*) RingPagesPtr
;
96 RingPagesPtr
+= sizeof *Ring
->Avail
.Ring
* QueueSize
;
98 Ring
->Avail
.UsedEvent
= (volatile VOID
*) RingPagesPtr
;
99 RingPagesPtr
+= sizeof *Ring
->Avail
.UsedEvent
;
101 RingPagesPtr
= (volatile UINT8
*) Ring
->Base
+
102 ALIGN_VALUE (RingPagesPtr
- (volatile UINT8
*) Ring
->Base
,
105 Ring
->Used
.Flags
= (volatile VOID
*) RingPagesPtr
;
106 RingPagesPtr
+= sizeof *Ring
->Used
.Flags
;
108 Ring
->Used
.Idx
= (volatile VOID
*) RingPagesPtr
;
109 RingPagesPtr
+= sizeof *Ring
->Used
.Idx
;
111 Ring
->Used
.UsedElem
= (volatile VOID
*) RingPagesPtr
;
112 RingPagesPtr
+= sizeof *Ring
->Used
.UsedElem
* QueueSize
;
114 Ring
->Used
.AvailEvent
= (volatile VOID
*) RingPagesPtr
;
115 RingPagesPtr
+= sizeof *Ring
->Used
.AvailEvent
;
117 Ring
->QueueSize
= QueueSize
;
124 Tear down the internal resources of a configured virtio ring.
126 The caller is responsible to stop the host from using this ring before
127 invoking this function: the VSTAT_DRIVER_OK bit must be clear in
130 @param[out] Ring The virtio ring to clean up.
139 FreePages (Ring
->Base
, Ring
->NumPages
);
140 SetMem (Ring
, sizeof *Ring
, 0x00);
146 Turn off interrupt notifications from the host, and prepare for appending
147 multiple descriptors to the virtio ring.
149 The calling driver must be in VSTAT_DRIVER_OK state.
151 @param[in,out] Ring The virtio ring we intend to append descriptors to.
153 @param[out] Indices The DESC_INDICES structure to initialize.
160 OUT DESC_INDICES
*Indices
164 // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.
165 // We're going to poll the answer, the host should not send an interrupt.
167 *Ring
->Avail
.Flags
= (UINT16
) VRING_AVAIL_F_NO_INTERRUPT
;
170 // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.
172 // Since we support only one in-flight descriptor chain, we can always build
173 // that chain starting at entry #0 of the descriptor table.
175 Indices
->HeadDescIdx
= 0;
176 Indices
->NextDescIdx
= Indices
->HeadDescIdx
;
182 Append a contiguous buffer for transmission / reception via the virtio ring.
184 This function implements the following section from virtio-0.9.5:
185 - 2.4.1.1 Placing Buffers into the Descriptor Table
187 Free space is taken as granted, since the individual drivers support only
188 synchronous requests and host side status is processed in lock-step with
189 request submission. It is the calling driver's responsibility to verify the
190 ring size in advance.
192 The caller is responsible for initializing *Indices with VirtioPrepare()
195 @param[in,out] Ring The virtio ring to append the buffer to, as a
198 @param[in] BufferPhysAddr (Guest pseudo-physical) start address of the
199 transmit / receive buffer.
201 @param[in] BufferSize Number of bytes to transmit or receive.
203 @param[in] Flags A bitmask of VRING_DESC_F_* flags. The caller
204 computes this mask dependent on further buffers to
205 append and transfer direction.
206 VRING_DESC_F_INDIRECT is unsupported. The
207 VRING_DESC.Next field is always set, but the host
208 only interprets it dependent on VRING_DESC_F_NEXT.
210 @param[in,out] Indices Indices->HeadDescIdx is not accessed.
211 On input, Indices->NextDescIdx identifies the next
212 descriptor to carry the buffer. On output,
213 Indices->NextDescIdx is incremented by one, modulo
221 IN UINTN BufferPhysAddr
,
222 IN UINT32 BufferSize
,
224 IN OUT DESC_INDICES
*Indices
227 volatile VRING_DESC
*Desc
;
229 Desc
= &Ring
->Desc
[Indices
->NextDescIdx
++ % Ring
->QueueSize
];
230 Desc
->Addr
= BufferPhysAddr
;
231 Desc
->Len
= BufferSize
;
233 Desc
->Next
= Indices
->NextDescIdx
% Ring
->QueueSize
;
239 Notify the host about the descriptor chain just built, and wait until the
242 @param[in] VirtIo The target virtio device to notify.
244 @param[in] VirtQueueId Identifies the queue for the target device.
246 @param[in,out] Ring The virtio ring with descriptors to submit.
248 @param[in] Indices Indices->NextDescIdx is not accessed.
249 Indices->HeadDescIdx identifies the head descriptor
250 of the descriptor chain.
253 @return Error code from VirtIo->SetQueueNotify() if it fails.
255 @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
261 IN VIRTIO_DEVICE_PROTOCOL
*VirtIo
,
262 IN UINT16 VirtQueueId
,
264 IN DESC_INDICES
*Indices
269 UINTN PollPeriodUsecs
;
272 // virtio-0.9.5, 2.4.1.2 Updating the Available Ring
274 // It is not exactly clear from the wording of the virtio-0.9.5
275 // specification, but each entry in the Available Ring references only the
276 // head descriptor of any given descriptor chain.
278 NextAvailIdx
= *Ring
->Avail
.Idx
;
279 Ring
->Avail
.Ring
[NextAvailIdx
++ % Ring
->QueueSize
] =
280 Indices
->HeadDescIdx
% Ring
->QueueSize
;
283 // virtio-0.9.5, 2.4.1.3 Updating the Index Field
286 *Ring
->Avail
.Idx
= NextAvailIdx
;
289 // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are
293 Status
= VirtIo
->SetQueueNotify (VirtIo
, VirtQueueId
);
294 if (EFI_ERROR (Status
)) {
299 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
300 // Wait until the host processes and acknowledges our descriptor chain. The
301 // condition we use for polling is greatly simplified and relies on the
302 // synchronous, lock-step progress.
304 // Keep slowing down until we reach a poll period of slightly above 1 ms.
308 while (*Ring
->Used
.Idx
!= NextAvailIdx
) {
309 gBS
->Stall (PollPeriodUsecs
); // calls AcpiTimerLib::MicroSecondDelay
311 if (PollPeriodUsecs
< 1024) {
312 PollPeriodUsecs
*= 2;