3 Utility functions used by virtio device drivers.
5 Copyright (C) 2012, Red Hat, Inc.
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <IndustryStandard/Pci22.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/MemoryAllocationLib.h>
22 #include <Library/VirtioLib.h>
27 Write a word into Region 0 of the device specified by PciIo.
29 Region 0 must be an iomem region. This is an internal function for the
30 driver-specific VIRTIO_CFG_WRITE() macros.
32 @param[in] PciIo Target PCI device.
34 @param[in] FieldOffset Destination offset.
36 @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.
38 @param[in] Value Little endian value to write, converted to UINT64.
39 The least significant FieldSize bytes will be used.
42 @return Status code returned by PciIo->Io.Write().
48 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
55 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
60 Width
= EfiPciIoWidthUint8
;
64 Width
= EfiPciIoWidthUint16
;
72 Width
= EfiPciIoWidthUint32
;
79 return PciIo
->Io
.Write (
92 Read a word from Region 0 of the device specified by PciIo.
94 Region 0 must be an iomem region. This is an internal function for the
95 driver-specific VIRTIO_CFG_READ() macros.
97 @param[in] PciIo Source PCI device.
99 @param[in] FieldOffset Source offset.
101 @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.
103 @param[in] BufferSize Number of bytes available in the target buffer. Must
106 @param[out] Buffer Target buffer.
109 @return Status code returned by PciIo->Io.Read().
115 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
116 IN UINTN FieldOffset
,
123 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
125 ASSERT (FieldSize
== BufferSize
);
130 Width
= EfiPciIoWidthUint8
;
134 Width
= EfiPciIoWidthUint16
;
142 Width
= EfiPciIoWidthUint32
;
149 return PciIo
->Io
.Read (
162 Configure a virtio ring.
164 This function sets up internal storage (the guest-host communication area)
165 and lays out several "navigation" (ie. no-ownership) pointers to parts of
168 Relevant sections from the virtio-0.9.5 spec:
170 - 2.3 Virtqueue Configuration.
172 @param[in] The number of descriptors to allocate for the
173 virtio ring, as requested by the host.
175 @param[out] Ring The virtio ring to set up.
177 @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous
178 pages for the requested QueueSize. Fields of
179 Ring have indeterminate value.
181 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base
182 (and nothing else) is responsible for
194 volatile UINT8
*RingPagesPtr
;
196 RingSize
= ALIGN_VALUE (
197 sizeof *Ring
->Desc
* QueueSize
+
198 sizeof *Ring
->Avail
.Flags
+
199 sizeof *Ring
->Avail
.Idx
+
200 sizeof *Ring
->Avail
.Ring
* QueueSize
+
201 sizeof *Ring
->Avail
.UsedEvent
,
204 RingSize
+= ALIGN_VALUE (
205 sizeof *Ring
->Used
.Flags
+
206 sizeof *Ring
->Used
.Idx
+
207 sizeof *Ring
->Used
.UsedElem
* QueueSize
+
208 sizeof *Ring
->Used
.AvailEvent
,
211 Ring
->NumPages
= EFI_SIZE_TO_PAGES (RingSize
);
212 Ring
->Base
= AllocatePages (Ring
->NumPages
);
213 if (Ring
->Base
== NULL
) {
214 return EFI_OUT_OF_RESOURCES
;
216 SetMem (Ring
->Base
, RingSize
, 0x00);
217 RingPagesPtr
= Ring
->Base
;
219 Ring
->Desc
= (volatile VOID
*) RingPagesPtr
;
220 RingPagesPtr
+= sizeof *Ring
->Desc
* QueueSize
;
222 Ring
->Avail
.Flags
= (volatile VOID
*) RingPagesPtr
;
223 RingPagesPtr
+= sizeof *Ring
->Avail
.Flags
;
225 Ring
->Avail
.Idx
= (volatile VOID
*) RingPagesPtr
;
226 RingPagesPtr
+= sizeof *Ring
->Avail
.Idx
;
228 Ring
->Avail
.Ring
= (volatile VOID
*) RingPagesPtr
;
229 RingPagesPtr
+= sizeof *Ring
->Avail
.Ring
* QueueSize
;
231 Ring
->Avail
.UsedEvent
= (volatile VOID
*) RingPagesPtr
;
232 RingPagesPtr
+= sizeof *Ring
->Avail
.UsedEvent
;
234 RingPagesPtr
= (volatile UINT8
*) Ring
->Base
+
235 ALIGN_VALUE (RingPagesPtr
- (volatile UINT8
*) Ring
->Base
,
238 Ring
->Used
.Flags
= (volatile VOID
*) RingPagesPtr
;
239 RingPagesPtr
+= sizeof *Ring
->Used
.Flags
;
241 Ring
->Used
.Idx
= (volatile VOID
*) RingPagesPtr
;
242 RingPagesPtr
+= sizeof *Ring
->Used
.Idx
;
244 Ring
->Used
.UsedElem
= (volatile VOID
*) RingPagesPtr
;
245 RingPagesPtr
+= sizeof *Ring
->Used
.UsedElem
* QueueSize
;
247 Ring
->Used
.AvailEvent
= (volatile VOID
*) RingPagesPtr
;
248 RingPagesPtr
+= sizeof *Ring
->Used
.AvailEvent
;
250 Ring
->QueueSize
= QueueSize
;
257 Tear down the internal resources of a configured virtio ring.
259 The caller is responsible to stop the host from using this ring before
260 invoking this function: the VSTAT_DRIVER_OK bit must be clear in
263 @param[out] Ring The virtio ring to clean up.
272 FreePages (Ring
->Base
, Ring
->NumPages
);
273 SetMem (Ring
, sizeof *Ring
, 0x00);
279 Append a contiguous buffer for transmission / reception via the virtio ring.
281 This function implements the following sections from virtio-0.9.5:
282 - 2.4.1.1 Placing Buffers into the Descriptor Table
283 - 2.4.1.2 Updating the Available Ring
285 Free space is taken as granted, since the individual drivers support only
286 synchronous requests and host side status is processed in lock-step with
287 request submission. It is the calling driver's responsibility to verify the
288 ring size in advance.
290 @param[in out] Ring The virtio ring to append the buffer to, as a
293 @param [in] BufferPhysAddr (Guest pseudo-physical) start address of the
294 transmit / receive buffer.
296 @param [in] BufferSize Number of bytes to transmit or receive.
298 @param [in] Flags A bitmask of VRING_DESC_F_* flags. The caller
299 computes this mask dependent on further buffers
300 to append and transfer direction.
301 VRING_DESC_F_INDIRECT is unsupported. The
302 VRING_DESC.Next field is always set, but the
303 host only interprets it dependent on
306 @param [in] HeadIdx The index identifying the head buffer (first
307 buffer appended) belonging to this same
310 @param [in out] NextAvailIdx On input, the index identifying the next
311 descriptor available to carry the buffer. On
312 output, incremented by one, modulo 2^16.
319 IN UINTN BufferPhysAddr
,
320 IN UINT32 BufferSize
,
323 IN OUT UINT16
*NextAvailIdx
326 volatile VRING_DESC
*Desc
;
328 Desc
= &Ring
->Desc
[*NextAvailIdx
% Ring
->QueueSize
];
329 Desc
->Addr
= BufferPhysAddr
;
330 Desc
->Len
= BufferSize
;
332 Ring
->Avail
.Ring
[(*NextAvailIdx
)++ % Ring
->QueueSize
] =
333 HeadIdx
% Ring
->QueueSize
;
334 Desc
->Next
= *NextAvailIdx
% Ring
->QueueSize
;